nnanh3-msal-browser
Version:
Thư viện đã custom của azure masl có common kèm trong
575 lines (572 loc) • 26.9 kB
JavaScript
/*! @azure/msal-common v4.5.1 2021-08-02 */
'use strict';
import { __awaiter, __generator, __assign } from '../_virtual/_tslib.js';
import { AuthorityType } from './AuthorityType.js';
import { isOpenIdConfigResponse } from './OpenIdConfigResponse.js';
import { UrlString } from '../url/UrlString.js';
import { ClientAuthError } from '../error/ClientAuthError.js';
import { Constants, AuthorityMetadataSource, RegionDiscoveryOutcomes } from '../utils/Constants.js';
import { ClientConfigurationError } from '../error/ClientConfigurationError.js';
import { ProtocolMode } from './ProtocolMode.js';
import { AuthorityMetadataEntity } from '../cache/entities/AuthorityMetadataEntity.js';
import { isCloudInstanceDiscoveryResponse } from './CloudInstanceDiscoveryResponse.js';
import { RegionDiscovery } from './RegionDiscovery.js';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/**
* The authority class validates the authority URIs used by the user, and retrieves the OpenID Configuration Data from the
* endpoint. It will store the pertinent config data in this object for use during token calls.
*/
var Authority = /** @class */ (function () {
function Authority(authority, networkInterface, cacheManager, authorityOptions) {
this.canonicalAuthority = authority;
this._canonicalAuthority.validateAsUri();
this.networkInterface = networkInterface;
this.cacheManager = cacheManager;
this.authorityOptions = authorityOptions;
this.regionDiscovery = new RegionDiscovery(networkInterface);
this.regionDiscoveryMetadata = { region_used: undefined, region_source: undefined, region_outcome: undefined };
}
Object.defineProperty(Authority.prototype, "authorityType", {
// See above for AuthorityType
get: function () {
var pathSegments = this.canonicalAuthorityUrlComponents.PathSegments;
if (pathSegments.length && pathSegments[0].toLowerCase() === Constants.ADFS) {
return AuthorityType.Adfs;
}
return AuthorityType.Default;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "protocolMode", {
/**
* ProtocolMode enum representing the way endpoints are constructed.
*/
get: function () {
return this.authorityOptions.protocolMode;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "options", {
/**
* Returns authorityOptions which can be used to reinstantiate a new authority instance
*/
get: function () {
return this.authorityOptions;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "canonicalAuthority", {
/**
* A URL that is the authority set by the developer
*/
get: function () {
return this._canonicalAuthority.urlString;
},
/**
* Sets canonical authority.
*/
set: function (url) {
this._canonicalAuthority = new UrlString(url);
this._canonicalAuthority.validateAsUri();
this._canonicalAuthorityUrlComponents = null;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "canonicalAuthorityUrlComponents", {
/**
* Get authority components.
*/
get: function () {
if (!this._canonicalAuthorityUrlComponents) {
this._canonicalAuthorityUrlComponents = this._canonicalAuthority.getUrlComponents();
}
return this._canonicalAuthorityUrlComponents;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "hostnameAndPort", {
/**
* Get hostname and port i.e. login.microsoftonline.com
*/
get: function () {
return this.canonicalAuthorityUrlComponents.HostNameAndPort.toLowerCase();
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "tenant", {
/**
* Get tenant for authority.
*/
get: function () {
return this.canonicalAuthorityUrlComponents.PathSegments[0];
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "authorizationEndpoint", {
/**
* OAuth /authorize endpoint for requests
*/
get: function () {
if (this.discoveryComplete()) {
var endpoint = this.replacePath(this.metadata.authorization_endpoint);
return this.replaceTenant(endpoint);
}
else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "tokenEndpoint", {
/**
* OAuth /token endpoint for requests
*/
get: function () {
if (this.discoveryComplete()) {
var endpoint = this.replacePath(this.metadata.token_endpoint);
return this.replaceTenant(endpoint);
}
else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "deviceCodeEndpoint", {
get: function () {
if (this.discoveryComplete()) {
var endpoint = this.replacePath(this.metadata.token_endpoint.replace("/token", "/devicecode"));
return this.replaceTenant(endpoint);
}
else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "endSessionEndpoint", {
/**
* OAuth logout endpoint for requests
*/
get: function () {
if (this.discoveryComplete()) {
var endpoint = this.replacePath(this.metadata.end_session_endpoint);
return this.replaceTenant(endpoint);
}
else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Authority.prototype, "selfSignedJwtAudience", {
/**
* OAuth issuer for requests
*/
get: function () {
if (this.discoveryComplete()) {
var endpoint = this.replacePath(this.metadata.issuer);
return this.replaceTenant(endpoint);
}
else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
},
enumerable: false,
configurable: true
});
/**
* Replaces tenant in url path with current tenant. Defaults to common.
* @param urlString
*/
Authority.prototype.replaceTenant = function (urlString) {
return urlString.replace(/{tenant}|{tenantid}/g, this.tenant);
};
/**
* Replaces path such as tenant or policy with the current tenant or policy.
* @param urlString
*/
Authority.prototype.replacePath = function (urlString) {
var endpoint = urlString;
var cachedAuthorityUrl = new UrlString(this.metadata.canonical_authority);
var cachedAuthorityParts = cachedAuthorityUrl.getUrlComponents().PathSegments;
var currentAuthorityParts = this.canonicalAuthorityUrlComponents.PathSegments;
currentAuthorityParts.forEach(function (currentPart, index) {
var cachedPart = cachedAuthorityParts[index];
if (currentPart !== cachedPart) {
endpoint = endpoint.replace("/" + cachedPart + "/", "/" + currentPart + "/");
}
});
return endpoint;
};
Object.defineProperty(Authority.prototype, "defaultOpenIdConfigurationEndpoint", {
/**
* The default open id configuration endpoint for any canonical authority.
*/
get: function () {
if (this.authorityType === AuthorityType.Adfs || this.protocolMode === ProtocolMode.OIDC) {
return this.canonicalAuthority + ".well-known/openid-configuration";
}
return this.canonicalAuthority + "v2.0/.well-known/openid-configuration";
},
enumerable: false,
configurable: true
});
/**
* Boolean that returns whethr or not tenant discovery has been completed.
*/
Authority.prototype.discoveryComplete = function () {
return !!this.metadata;
};
/**
* Perform endpoint discovery to discover aliases, preferred_cache, preferred_network
* and the /authorize, /token and logout endpoints.
*/
Authority.prototype.resolveEndpointsAsync = function () {
return __awaiter(this, void 0, void 0, function () {
var metadataEntity, cloudDiscoverySource, endpointSource, cacheKey;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
metadataEntity = this.cacheManager.getAuthorityMetadataByAlias(this.hostnameAndPort);
if (!metadataEntity) {
metadataEntity = new AuthorityMetadataEntity();
metadataEntity.updateCanonicalAuthority(this.canonicalAuthority);
}
return [4 /*yield*/, this.updateCloudDiscoveryMetadata(metadataEntity)];
case 1:
cloudDiscoverySource = _a.sent();
this.canonicalAuthority = this.canonicalAuthority.replace(this.hostnameAndPort, metadataEntity.preferred_network);
return [4 /*yield*/, this.updateEndpointMetadata(metadataEntity)];
case 2:
endpointSource = _a.sent();
if (cloudDiscoverySource !== AuthorityMetadataSource.CACHE && endpointSource !== AuthorityMetadataSource.CACHE) {
// Reset the expiration time unless both values came from a successful cache lookup
metadataEntity.resetExpiresAt();
metadataEntity.updateCanonicalAuthority(this.canonicalAuthority);
}
cacheKey = this.cacheManager.generateAuthorityMetadataCacheKey(metadataEntity.preferred_cache);
this.cacheManager.setAuthorityMetadata(cacheKey, metadataEntity);
this.metadata = metadataEntity;
return [2 /*return*/];
}
});
});
};
/**
* Update AuthorityMetadataEntity with new endpoints and return where the information came from
* @param metadataEntity
*/
Authority.prototype.updateEndpointMetadata = function (metadataEntity) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var metadata, autodetectedRegionName, azureRegion;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
metadata = this.getEndpointMetadataFromConfig();
if (metadata) {
metadataEntity.updateEndpointMetadata(metadata, false);
return [2 /*return*/, AuthorityMetadataSource.CONFIG];
}
if (this.isAuthoritySameType(metadataEntity) && metadataEntity.endpointsFromNetwork && !metadataEntity.isExpired()) {
// No need to update
return [2 /*return*/, AuthorityMetadataSource.CACHE];
}
return [4 /*yield*/, this.getEndpointMetadataFromNetwork()];
case 1:
metadata = _b.sent();
if (!metadata) return [3 /*break*/, 4];
if (!((_a = this.authorityOptions.azureRegionConfiguration) === null || _a === void 0 ? void 0 : _a.azureRegion)) return [3 /*break*/, 3];
return [4 /*yield*/, this.regionDiscovery.detectRegion(this.authorityOptions.azureRegionConfiguration.environmentRegion, this.regionDiscoveryMetadata)];
case 2:
autodetectedRegionName = _b.sent();
azureRegion = this.authorityOptions.azureRegionConfiguration.azureRegion === Constants.AZURE_REGION_AUTO_DISCOVER_FLAG
? autodetectedRegionName
: this.authorityOptions.azureRegionConfiguration.azureRegion;
if (this.authorityOptions.azureRegionConfiguration.azureRegion === Constants.AZURE_REGION_AUTO_DISCOVER_FLAG) {
this.regionDiscoveryMetadata.region_outcome = autodetectedRegionName ?
RegionDiscoveryOutcomes.AUTO_DETECTION_REQUESTED_SUCCESSFUL :
RegionDiscoveryOutcomes.AUTO_DETECTION_REQUESTED_FAILED;
}
else {
if (autodetectedRegionName) {
this.regionDiscoveryMetadata.region_outcome = (this.authorityOptions.azureRegionConfiguration.azureRegion === autodetectedRegionName) ?
RegionDiscoveryOutcomes.CONFIGURED_MATCHES_DETECTED :
RegionDiscoveryOutcomes.CONFIGURED_NOT_DETECTED;
}
else {
this.regionDiscoveryMetadata.region_outcome = RegionDiscoveryOutcomes.CONFIGURED_NO_AUTO_DETECTION;
}
}
if (azureRegion) {
this.regionDiscoveryMetadata.region_used = azureRegion;
metadata = Authority.replaceWithRegionalInformation(metadata, azureRegion);
}
_b.label = 3;
case 3:
metadataEntity.updateEndpointMetadata(metadata, true);
return [2 /*return*/, AuthorityMetadataSource.NETWORK];
case 4: throw ClientAuthError.createUnableToGetOpenidConfigError(this.defaultOpenIdConfigurationEndpoint);
}
});
});
};
/**
* Compares the number of url components after the domain to determine if the cached authority metadata can be used for the requested authority
* Protects against same domain different authority such as login.microsoftonline.com/tenant and login.microsoftonline.com/tfp/tenant/policy
* @param metadataEntity
*/
Authority.prototype.isAuthoritySameType = function (metadataEntity) {
var cachedAuthorityUrl = new UrlString(metadataEntity.canonical_authority);
var cachedParts = cachedAuthorityUrl.getUrlComponents().PathSegments;
return cachedParts.length === this.canonicalAuthorityUrlComponents.PathSegments.length;
};
/**
* Parse authorityMetadata config option
*/
Authority.prototype.getEndpointMetadataFromConfig = function () {
if (this.authorityOptions.authorityMetadata) {
try {
return JSON.parse(this.authorityOptions.authorityMetadata);
}
catch (e) {
throw ClientConfigurationError.createInvalidAuthorityMetadataError();
}
}
return null;
};
/**
* Gets OAuth endpoints from the given OpenID configuration endpoint.
*/
Authority.prototype.getEndpointMetadataFromNetwork = function () {
return __awaiter(this, void 0, void 0, function () {
var response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
return [4 /*yield*/, this.networkInterface.sendGetRequestAsync(this.defaultOpenIdConfigurationEndpoint)];
case 1:
response = _a.sent();
return [2 /*return*/, isOpenIdConfigResponse(response.body) ? response.body : null];
case 2:
_a.sent();
return [2 /*return*/, null];
case 3: return [2 /*return*/];
}
});
});
};
/**
* Updates the AuthorityMetadataEntity with new aliases, preferred_network and preferred_cache and returns where the information was retrived from
* @param cachedMetadata
* @param newMetadata
*/
Authority.prototype.updateCloudDiscoveryMetadata = function (metadataEntity) {
return __awaiter(this, void 0, void 0, function () {
var metadata;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
metadata = this.getCloudDiscoveryMetadataFromConfig();
if (metadata) {
metadataEntity.updateCloudDiscoveryMetadata(metadata, false);
return [2 /*return*/, AuthorityMetadataSource.CONFIG];
}
// If The cached metadata came from config but that config was not passed to this instance, we must go to the network
if (this.isAuthoritySameType(metadataEntity) && metadataEntity.aliasesFromNetwork && !metadataEntity.isExpired()) {
// No need to update
return [2 /*return*/, AuthorityMetadataSource.CACHE];
}
return [4 /*yield*/, this.getCloudDiscoveryMetadataFromNetwork()];
case 1:
metadata = _a.sent();
if (metadata) {
metadataEntity.updateCloudDiscoveryMetadata(metadata, true);
return [2 /*return*/, AuthorityMetadataSource.NETWORK];
}
else {
// Metadata could not be obtained from config, cache or network
throw ClientConfigurationError.createUntrustedAuthorityError();
}
}
});
});
};
/**
* Parse cloudDiscoveryMetadata config or check knownAuthorities
*/
Authority.prototype.getCloudDiscoveryMetadataFromConfig = function () {
// Check if network response was provided in config
if (this.authorityOptions.cloudDiscoveryMetadata) {
try {
var parsedResponse = JSON.parse(this.authorityOptions.cloudDiscoveryMetadata);
var metadata = Authority.getCloudDiscoveryMetadataFromNetworkResponse(parsedResponse.metadata, this.hostnameAndPort);
if (metadata) {
return metadata;
}
}
catch (e) {
throw ClientConfigurationError.createInvalidCloudDiscoveryMetadataError();
}
}
// If cloudDiscoveryMetadata is empty or does not contain the host, check knownAuthorities
if (this.isInKnownAuthorities()) {
return Authority.createCloudDiscoveryMetadataFromHost(this.hostnameAndPort);
}
return null;
};
/**
* Called to get metadata from network if CloudDiscoveryMetadata was not populated by config
* @param networkInterface
*/
Authority.prototype.getCloudDiscoveryMetadataFromNetwork = function () {
return __awaiter(this, void 0, void 0, function () {
var instanceDiscoveryEndpoint, match, response, metadata;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
instanceDiscoveryEndpoint = "" + Constants.AAD_INSTANCE_DISCOVERY_ENDPT + this.canonicalAuthority + "oauth2/v2.0/authorize";
match = null;
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.networkInterface.sendGetRequestAsync(instanceDiscoveryEndpoint)];
case 2:
response = _a.sent();
metadata = isCloudInstanceDiscoveryResponse(response.body) ? response.body.metadata : [];
if (metadata.length === 0) {
// If no metadata is returned, authority is untrusted
return [2 /*return*/, null];
}
match = Authority.getCloudDiscoveryMetadataFromNetworkResponse(metadata, this.hostnameAndPort);
return [3 /*break*/, 4];
case 3:
_a.sent();
return [2 /*return*/, null];
case 4:
if (!match) {
// Custom Domain scenario, host is trusted because Instance Discovery call succeeded
match = Authority.createCloudDiscoveryMetadataFromHost(this.hostnameAndPort);
}
return [2 /*return*/, match];
}
});
});
};
/**
* Helper function to determine if this host is included in the knownAuthorities config option
*/
Authority.prototype.isInKnownAuthorities = function () {
var _this = this;
var matches = this.authorityOptions.knownAuthorities.filter(function (authority) {
return UrlString.getDomainFromUrl(authority).toLowerCase() === _this.hostnameAndPort;
});
return matches.length > 0;
};
/**
* Creates cloud discovery metadata object from a given host
* @param host
*/
Authority.createCloudDiscoveryMetadataFromHost = function (host) {
return {
preferred_network: host,
preferred_cache: host,
aliases: [host]
};
};
/**
* Searches instance discovery network response for the entry that contains the host in the aliases list
* @param response
* @param authority
*/
Authority.getCloudDiscoveryMetadataFromNetworkResponse = function (response, authority) {
for (var i = 0; i < response.length; i++) {
var metadata = response[i];
if (metadata.aliases.indexOf(authority) > -1) {
return metadata;
}
}
return null;
};
/**
* helper function to generate environment from authority object
*/
Authority.prototype.getPreferredCache = function () {
if (this.discoveryComplete()) {
return this.metadata.preferred_cache;
}
else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
};
/**
* Returns whether or not the provided host is an alias of this authority instance
* @param host
*/
Authority.prototype.isAlias = function (host) {
return this.metadata.aliases.indexOf(host) > -1;
};
/**
* Checks whether the provided host is that of a public cloud authority
*
* @param authority string
* @returns bool
*/
Authority.isPublicCloudAuthority = function (host) {
return Constants.KNOWN_PUBLIC_CLOUDS.indexOf(host) >= 0;
};
/**
* Rebuild the authority string with the region
*
* @param host string
* @param region string
*/
Authority.buildRegionalAuthorityString = function (host, region, queryString) {
// Create and validate a Url string object with the initial authority string
var authorityUrlInstance = new UrlString(host);
authorityUrlInstance.validateAsUri();
var authorityUrlParts = authorityUrlInstance.getUrlComponents();
var hostNameAndPort = region + "." + authorityUrlParts.HostNameAndPort;
if (this.isPublicCloudAuthority(authorityUrlParts.HostNameAndPort)) {
hostNameAndPort = region + "." + Constants.REGIONAL_AUTH_PUBLIC_CLOUD_SUFFIX;
}
// Include the query string portion of the url
var url = UrlString.constructAuthorityUriFromObject(__assign(__assign({}, authorityUrlInstance.getUrlComponents()), { HostNameAndPort: hostNameAndPort })).urlString;
// Add the query string if a query string was provided
if (queryString)
return url + "?" + queryString;
return url;
};
/**
* Replace the endpoints in the metadata object with their regional equivalents.
*
* @param metadata OpenIdConfigResponse
* @param azureRegion string
*/
Authority.replaceWithRegionalInformation = function (metadata, azureRegion) {
metadata.authorization_endpoint = Authority.buildRegionalAuthorityString(metadata.authorization_endpoint, azureRegion);
// TODO: Enquire on whether we should leave the query string or remove it before releasing the feature
metadata.token_endpoint = Authority.buildRegionalAuthorityString(metadata.token_endpoint, azureRegion, "allowestsrnonmsi=true");
metadata.end_session_endpoint = Authority.buildRegionalAuthorityString(metadata.end_session_endpoint, azureRegion);
return metadata;
};
return Authority;
}());
export { Authority };
//# sourceMappingURL=Authority.js.map