Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ba49410
Initial Commit
tnorling May 1, 2020
e5764bc
Merge branch 'dev' into cloud-discovery
tnorling May 13, 2020
d2bf765
Merge branch 'dev' into cloud-discovery
tnorling May 19, 2020
968c1b3
Merge branch 'authority-metadata-openid-perf' of https://github.com/A…
tnorling May 19, 2020
a9b9853
Move setup functions to Factory
tnorling May 19, 2020
e90cd4e
Update unit tests
tnorling May 20, 2020
c75b961
Merge branch 'authority-metadata-openid-perf' of https://github.com/A…
tnorling May 20, 2020
453bad8
Resolve lint errors
tnorling May 20, 2020
85d1736
Move validation of Authority to Factory
tnorling May 21, 2020
e0fc794
Add TrustedHostList getter
tnorling May 21, 2020
a190f8a
Update Error message
tnorling May 21, 2020
72e213b
Separate async network call
tnorling May 21, 2020
acebe0f
Fix Trusted Check
tnorling May 21, 2020
19ab0dd
Unit Tests
tnorling May 21, 2020
dc93c20
Merge branch 'dev' of https://github.com/AzureAD/microsoft-authentica…
tnorling May 21, 2020
b179c4d
Move TrustedAuthority to its own class
tnorling May 22, 2020
4d11b85
Clean up test
tnorling May 22, 2020
ff06f8b
Fix context
tnorling May 22, 2020
79e8fce
Merge branch 'dev' into cloud-discovery
tnorling May 26, 2020
80c4b6d
Add tests
tnorling May 26, 2020
22b125e
Merge branch 'dev' into cloud-discovery
tnorling Jun 1, 2020
acb0a51
Initiate cloud discovery in Constructor
tnorling Jun 2, 2020
69c53db
Fix lint errors
tnorling Jun 2, 2020
bc50c5a
Fix tests
tnorling Jun 2, 2020
01212c6
Revert "Fix tests"
tnorling Jun 3, 2020
ea9fab0
Revert "Fix lint errors"
tnorling Jun 3, 2020
e645c9e
Revert "Initiate cloud discovery in Constructor"
tnorling Jun 3, 2020
6e098e3
Merge branch 'dev' into cloud-discovery
tnorling Jun 3, 2020
c0fa200
Merge branch 'dev' of https://github.com/AzureAD/microsoft-authentica…
tnorling Jun 15, 2020
2e16854
Addressing feedback
tnorling Jun 15, 2020
84dd6a2
Merge branch 'dev' into cloud-discovery
tnorling Jun 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge branch 'authority-metadata-openid-perf' of https://github.com/A…
  • Loading branch information
tnorling committed May 20, 2020
commit c75b9614270499a841bd8afe7d5322e629d1c73e
28 changes: 28 additions & 0 deletions lib/msal-core/docs/performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Performance

This document will outline techniques your application can use to improve the performance of acquire tokens using MSAL.js.

## Bypass authority metadata resolution

By default, during the process of retrieving a token MSAL.js will make two network requests to retrieve metadata from the authority configured for the request. If you would like to skip those network requests, you can provide the required metadata in the configuration of `UserAgentApplication`.

**Important:** It is your application's responsibility to ensure it is using correct, up-to-date authority metadata. Failure to do so may result in your application not working correctly.

Instructions:

1. Determine the authorize endpoint for your authority. For example, if you are using `https://login.microsoftonline.com/common/`, the authorize endpoint is `https://login.microsoftonline.com/common/oauth2/v2.0/authorize`.
2. Determine the instance discovery endpoint for your authority. The instance discovery API is located at `https://login.microsoftonline.com/common/discovery/instance?api-version=1.0&authorization_endpoint={authorizeEndpoint}`. If you are using the `common` endpoint, this url is `https://login.microsoftonline.com/common/discovery/instance?api-version=1.0&authorization_endpoint=https://login.microsoftonline.com/common/oauth2/v2.0/authorize`.
3. Make a request to the instance discovery endpoint.
4. Parse the `tenant_discovery_endpoint` property from the response.
5. Make a request to the url for the `tenant_discovery_endpoint` property.
6. Take the **entire** response and provide the raw JSON string as the `auth.authorityMetadata` property for `UserAgentApplication`. It can also be passed per-request as a part of `AuthenticationParameters`.

Example:

```js
const msalInstance = new msal.UserAgentApplication({
auth: {
authorityMetadata: '{"token_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/common/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/{tenantid}/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/authorize","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"tenant_region_scope":null,"cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}'
}
});
```
29 changes: 16 additions & 13 deletions lib/msal-core/src/UserAgentApplication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export class UserAgentApplication {
this.telemetryManager = this.getTelemetryManagerFromConfig(this.config.system.telemetry, this.clientId);

AuthorityFactory.setKnownAuthorities(this.config.auth.validateAuthority, this.config.auth.knownAuthorities, this.telemetryManager);
AuthorityFactory.parseAuthorityMetadata(this.config.auth.authority, this.config.auth.authorityMetadata);
AuthorityFactory.saveMetadataFromConfig(this.config.auth.authority, this.config.auth.authorityMetadata);

// if no authority is passed, set the default: "https://login.microsoftonline.com/common"
this.authority = this.config.auth.authority || DEFAULT_AUTHORITY;
Expand Down Expand Up @@ -518,7 +518,7 @@ export class UserAgentApplication {
try {
if (!acquireTokenAuthority.hasCachedMetadata()) {
this.logger.verbose("No cached metadata for authority");
await AuthorityFactory.resolveAuthorityAsync(acquireTokenAuthority, this.telemetryManager, request.correlationId);
await AuthorityFactory.saveMetadataFromNetwork(acquireTokenAuthority, this.telemetryManager, request.correlationId);
} else {
this.logger.verbose("Cached metadata found for authority");
}
Expand Down Expand Up @@ -748,18 +748,21 @@ export class UserAgentApplication {
serverAuthenticationRequest.authorityInstance = request.authority ? AuthorityFactory.CreateInstance(request.authority, this.config.auth.validateAuthority, request.authorityMetadata) : this.authorityInstance;
}

this.logger.verbosePii(`Authority instance: ${serverAuthenticationRequest.authority}`);

try {
if (!serverAuthenticationRequest.authorityInstance.hasCachedMetadata()) {
this.logger.verbose("No cached metadata for authority");
await AuthorityFactory.resolveAuthorityAsync(serverAuthenticationRequest.authorityInstance, this.telemetryManager, request.correlationId);
await AuthorityFactory.saveMetadataFromNetwork(serverAuthenticationRequest.authorityInstance, this.telemetryManager, request.correlationId);
this.logger.verbose("Authority has been updated with endpoint discovery response");
} else {
this.logger.verbose("Cached metadata found for authority");
}

/*
* refresh attempt with iframe
* Already renewing for this scope, callback when we get the token.
*/
* refresh attempt with iframe
* Already renewing for this scope, callback when we get the token.
*/
if (window.activeRenewals[requestSignature]) {
this.logger.verbose("Renew token for scope and authority: " + requestSignature + " is in progress. Registering callback");
// Active renewals contains the state for each renewal.
Expand All @@ -768,15 +771,15 @@ export class UserAgentApplication {
else {
if (request.scopes && request.scopes.indexOf(this.clientId) > -1 && request.scopes.length === 1) {
/*
* App uses idToken to send to api endpoints
* Default scope is tracked as clientId to store this token
*/
this.logger.verbose("renewing idToken");
* App uses idToken to send to api endpoints
* Default scope is tracked as clientId to store this token
*/
this.logger.verbose("Renewing idToken");
this.silentLogin = true;
this.renewIdToken(requestSignature, resolve, reject, account, serverAuthenticationRequest);
} else {
// renew access token
this.logger.verbose("renewing accesstoken");
this.logger.verbose("Renewing accesstoken");
this.renewToken(requestSignature, resolve, reject, account, serverAuthenticationRequest);
}
}
Expand Down Expand Up @@ -991,12 +994,12 @@ export class UserAgentApplication {
try {
if (!this.authorityInstance.hasCachedMetadata()) {
this.logger.verbose("No cached metadata for authority");
await AuthorityFactory.resolveAuthorityAsync(this.authorityInstance, this.telemetryManager, correlationId);
await AuthorityFactory.saveMetadataFromNetwork(this.authorityInstance, this.telemetryManager, correlationId);
} else {
this.logger.verbose("Cached metadata found for authority");
}

const correlationIdParam = `client-request-id=${requestCorrelationId}`
const correlationIdParam = `client-request-id=${requestCorrelationId}`;

const postLogoutQueryParam = this.getPostLogoutRedirectUri()
? `&post_logout_redirect_uri=${encodeURIComponent(this.getPostLogoutRedirectUri())}`
Expand Down
8 changes: 4 additions & 4 deletions lib/msal-core/src/authority/AuthorityFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ import HttpEvent from '../telemetry/HttpEvent';
export class AuthorityFactory {
private static metadataMap = new Map<string, ITenantDiscoveryResponse>();

public static async resolveAuthorityAsync(authorityInstance: Authority, telemetryManager: TelemetryManager, correlationId: string): Promise<ITenantDiscoveryResponse> {
public static async saveMetadataFromNetwork(authorityInstance: Authority, telemetryManager: TelemetryManager, correlationId: string): Promise<ITenantDiscoveryResponse> {
const metadata = await authorityInstance.resolveEndpointsAsync(telemetryManager, correlationId);
this.metadataMap.set(authorityInstance.CanonicalAuthority, metadata);
return metadata;
}

public static getAuthorityMetadata(authorityUrl: string) {
public static getMetadata(authorityUrl: string) {
return this.metadataMap.get(authorityUrl);
}

public static parseAuthorityMetadata(authorityUrl: string, authorityMetadataJson: string) {
public static saveMetadataFromConfig(authorityUrl: string, authorityMetadataJson: string) {
try {
if (authorityMetadataJson) {
const parsedMetadata = JSON.parse(authorityMetadataJson) as OpenIdConfiguration;
Expand Down Expand Up @@ -101,7 +101,7 @@ export class AuthorityFactory {

if (authorityMetadata) {
// todo: log statements
this.parseAuthorityMetadata(authorityUrl, authorityMetadata);
this.saveMetadataFromConfig(authorityUrl, authorityMetadata);
}

return new Authority(authorityUrl, validateAuthority, this.metadataMap.get(authorityUrl));
Expand Down
2 changes: 1 addition & 1 deletion lib/msal-core/src/authority/ITenantDiscoveryResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ export type OpenIdConfiguration = {
authorization_endpoint: string,
end_session_endpoint: string,
issuer: string
}
};
14 changes: 7 additions & 7 deletions lib/msal-core/test/authority/AuthorityFactory.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ describe("AuthorityFactory.ts Class", function () {
expect(stubbedHostList).to.have.length(3);
});

describe("parseAuthorityMetadata", () => {
describe("saveMetadataFromConfig", () => {
it("does nothing if json is falsey", () => {
AuthorityFactory.parseAuthorityMetadata(TEST_CONFIG.validAuthority, "");
expect(AuthorityFactory.getAuthorityMetadata(TEST_CONFIG.validAuthority)).to.be.undefined;
AuthorityFactory.saveMetadataFromConfig(TEST_CONFIG.validAuthority, "");
expect(AuthorityFactory.getMetadata(TEST_CONFIG.validAuthority)).to.be.undefined;
});

it("throws if invalid json is provided", done => {
try {
AuthorityFactory.parseAuthorityMetadata(TEST_CONFIG.validAuthority, "invalid-json");
AuthorityFactory.saveMetadataFromConfig(TEST_CONFIG.validAuthority, "invalid-json");
} catch (e) {
expect(e).instanceOf(ClientConfigurationError);
expect((e as ClientConfigurationError).errorCode).to.equal("authority_metadata_error");
Expand All @@ -80,7 +80,7 @@ describe("AuthorityFactory.ts Class", function () {

it("throws if json is missing required keys", done => {
try {
AuthorityFactory.parseAuthorityMetadata(TEST_CONFIG.validAuthority, "{}");
AuthorityFactory.saveMetadataFromConfig(TEST_CONFIG.validAuthority, "{}");
} catch (e) {
expect(e).instanceOf(ClientConfigurationError);
expect((e as ClientConfigurationError).errorCode).to.equal("authority_metadata_error");
Expand All @@ -91,9 +91,9 @@ describe("AuthorityFactory.ts Class", function () {
});

it("parses and stores metadata", () => {
AuthorityFactory.parseAuthorityMetadata(TEST_CONFIG.validAuthority, JSON.stringify(OPENID_CONFIGURATION));
AuthorityFactory.saveMetadataFromConfig(TEST_CONFIG.validAuthority, JSON.stringify(OPENID_CONFIGURATION));

expect(AuthorityFactory.getAuthorityMetadata(TEST_CONFIG.validAuthority)).to.deep.equal(TENANT_DISCOVERY_RESPONSE);
expect(AuthorityFactory.getMetadata(TEST_CONFIG.validAuthority)).to.deep.equal(TENANT_DISCOVERY_RESPONSE);
});
});
});
You are viewing a condensed version of this merge commit. You can view the full changes here.