Skip to content

Commit fd01dd9

Browse files
Changes:
* Implemented Authentication Handler Options * Implemented Authentication Provider Options
1 parent 7ec57c6 commit fd01dd9

13 files changed

+222
-30
lines changed

spec/DummyAuthenticationProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class DummyAuthenticationProvider implements AuthenticationProvider {
2323
* To get the access token
2424
* @returns The promise that resolves to an access token
2525
*/
26-
public async getAccessToken(): Promise<any> {
26+
public async getAccessToken(): Promise<string> {
2727
const token = "DUMMY_TOKEN";
2828
return Promise.resolve(token);
2929
}

spec/middleware/AuthenticationHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe("AuthenticationHandler.ts", async () => {
1818
describe("Constructor", () => {
1919
it("Should return an AuthenticationHandler for given AuthenticationProvider", () => {
2020
assert.isTrue(authHandler instanceof AuthenticationHandler);
21-
assert.equal(authHandler["authProvider"], dummyAuthProvider);
21+
assert.equal(authHandler["authenticationProvider"], dummyAuthProvider);
2222
});
2323
});
2424
/* tslint:enable: no-string-literal */
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* -------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
4+
* See License in the project root for license information.
5+
* -------------------------------------------------------------------------------------------
6+
*/
7+
8+
import { assert } from "chai";
9+
10+
import { AuthenticationHandlerOptions } from "../../src/middleware/options/AuthenticationHandlerOptions";
11+
import { MSALAuthenticationProviderOptions } from "../../src/MSALAuthenticationProviderOptions";
12+
import { DummyAuthenticationProvider } from "../DummyAuthenticationProvider";
13+
14+
describe("AuthenticationHandlerOptions.ts", () => {
15+
const dummyAuthProvider = new DummyAuthenticationProvider();
16+
const msalAuthProviderOptions = new MSALAuthenticationProviderOptions([]);
17+
it("Should create an instance with all the given options", () => {
18+
const options = new AuthenticationHandlerOptions(dummyAuthProvider, msalAuthProviderOptions);
19+
assert.equal(options.authenticationProvider, dummyAuthProvider);
20+
assert.equal(options.authenticationProviderOptions, msalAuthProviderOptions);
21+
});
22+
23+
it("Should be undefined value if no value is passed", () => {
24+
const options = new AuthenticationHandlerOptions(undefined, msalAuthProviderOptions);
25+
assert.isUndefined(options.authenticationProvider);
26+
assert.equal(options.authenticationProviderOptions, msalAuthProviderOptions);
27+
});
28+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* -------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
4+
* See License in the project root for license information.
5+
* -------------------------------------------------------------------------------------------
6+
*/
7+
8+
import { assert } from "chai";
9+
10+
import { MSALAuthenticationProviderOptions } from "../../src/MSALAuthenticationProviderOptions";
11+
12+
describe("MSALAuthenticationProviderOptions.ts", () => {
13+
it("Should create an instance with all the given options", () => {
14+
const scopes = ["dummy.scope"];
15+
const options = new MSALAuthenticationProviderOptions(scopes);
16+
assert.isDefined(options.scopes);
17+
assert.equal(options.scopes, scopes);
18+
});
19+
});

src/IAuthenticationProvider.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,18 @@
55
* -------------------------------------------------------------------------------------------
66
*/
77

8+
import { AuthenticationProviderOptions } from "./IAuthenticationProviderOptions";
9+
810
/**
911
* @interface
1012
* A signature representing Authentication provider
11-
* @property {Function} getAccessTokenWithCompletion - The function to get the access token from the authentication provider
13+
* @property {Function} getAccessToken - The function to get the access token from the authentication provider
1214
*/
1315
export interface AuthenticationProvider {
14-
getAccessToken: () => Promise<any>;
16+
/**
17+
* To get access token from the authentication provider
18+
* @param {AuthenticationProviderOptions} [authenticationProviderOptions] - The authentication provider options instance
19+
* @returns A promise that resolves to an access token
20+
*/
21+
getAccessToken: (authenticationProviderOptions?: AuthenticationProviderOptions) => Promise<string>;
1522
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* -------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
4+
* See License in the project root for license information.
5+
* -------------------------------------------------------------------------------------------
6+
*/
7+
8+
/**
9+
* @interface
10+
* A signature represents the Authentication provider options
11+
* @property {string[]} [scopes] - The array of scopes
12+
*/
13+
export interface AuthenticationProviderOptions {
14+
scopes?: string[];
15+
}

src/MSALAuthenticationProvider.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import { UserAgentApplication } from "msal";
1313

1414
import { AuthenticationProvider } from "./IAuthenticationProvider";
15+
import { AuthenticationProviderOptions } from "./IAuthenticationProviderOptions";
16+
import { MSALAuthenticationProviderOptions } from "./MSALAuthenticationProviderOptions";
1517

1618
/**
1719
* @class
@@ -57,26 +59,35 @@ export class MSALAuthenticationProvider implements AuthenticationProvider {
5759
* @public
5860
* @async
5961
* To get the access token
62+
* @param {AuthenticationProviderOptions} authenticationProviderOptions - The authentication provider options object
6063
* @returns The promise that resolves to an access token
6164
*/
62-
public async getAccessToken(): Promise<any> {
63-
if (this.scopes.length === 0) {
65+
public async getAccessToken(authenticationProviderOptions?: AuthenticationProviderOptions): Promise<string> {
66+
const options = authenticationProviderOptions as MSALAuthenticationProviderOptions;
67+
let scopes: string[];
68+
if (typeof options !== "undefined") {
69+
scopes = options.scopes;
70+
}
71+
if (typeof scopes === "undefined" || scopes.length === 0) {
72+
scopes = this.scopes;
73+
}
74+
if (scopes.length === 0) {
6475
const error = new Error();
6576
error.name = "EmptyScopes";
6677
error.message = "Scopes cannot be empty, Please provide a scope";
6778
throw error;
6879
}
6980
try {
70-
const accessToken: string = await this.userAgentApplication.acquireTokenSilent(this.scopes);
81+
const accessToken: string = await this.userAgentApplication.acquireTokenSilent(scopes);
7182
return accessToken;
7283
} catch (errorMsg) {
7384
try {
74-
const idToken: string = await this.userAgentApplication.loginPopup(this.scopes);
85+
const idToken: string = await this.userAgentApplication.loginPopup(scopes);
7586
try {
76-
const accessToken: string = await this.userAgentApplication.acquireTokenSilent(this.scopes);
87+
const accessToken: string = await this.userAgentApplication.acquireTokenSilent(scopes);
7788
return accessToken;
7889
} catch (error) {
79-
const accessToken: string = await this.userAgentApplication.acquireTokenPopup(this.scopes);
90+
const accessToken: string = await this.userAgentApplication.acquireTokenPopup(scopes);
8091
return accessToken;
8192
}
8293
} catch (errorMsg) {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* -------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
4+
* See License in the project root for license information.
5+
* -------------------------------------------------------------------------------------------
6+
*/
7+
8+
/**
9+
* @module MSALAuthenticationProviderOptions
10+
*/
11+
12+
import { AuthenticationProviderOptions } from "./IAuthenticationProviderOptions";
13+
14+
/**
15+
* @class
16+
* @implements AuthenticationProviderOptions
17+
* Class representing MSALAuthenticationProviderOptions
18+
*/
19+
export class MSALAuthenticationProviderOptions implements AuthenticationProviderOptions {
20+
/**
21+
* @public
22+
* A member holding array of scopes
23+
*/
24+
public scopes: string[];
25+
26+
/**
27+
* @public
28+
* @constructor
29+
* To create an instance of MSALAuthenticationProviderOptions
30+
* @param {string[]} scopes - An array of scopes
31+
* @returns An instance of MSALAuthenticationProviderOptions
32+
*/
33+
public constructor(scopes: string[]) {
34+
this.scopes = scopes;
35+
}
36+
}

src/browser/MSALAuthenticationProvider.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
*/
1111

1212
import { AuthenticationProvider } from "../IAuthenticationProvider";
13+
import { AuthenticationProviderOptions } from "../IAuthenticationProviderOptions";
14+
import { MSALAuthenticationProviderOptions } from "../MSALAuthenticationProviderOptions";
1315

1416
/**
1517
* @constant
@@ -63,26 +65,35 @@ export class MSALAuthenticationProvider implements AuthenticationProvider {
6365
* @public
6466
* @async
6567
* To get the access token
68+
* @param {AuthenticationProviderOptions} authenticationProviderOptions - The authentication provider options object
6669
* @returns The promise that resolves to an access token
6770
*/
68-
public async getAccessToken(): Promise<any> {
69-
if (this.scopes.length === 0) {
71+
public async getAccessToken(authenticationProviderOptions?: AuthenticationProviderOptions): Promise<string> {
72+
const options = authenticationProviderOptions as MSALAuthenticationProviderOptions;
73+
let scopes: string[];
74+
if (typeof options !== "undefined") {
75+
scopes = options.scopes;
76+
}
77+
if (typeof scopes === "undefined" || scopes.length === 0) {
78+
scopes = this.scopes;
79+
}
80+
if (scopes.length === 0) {
7081
const error = new Error();
7182
error.name = "EmptyScopes";
7283
error.message = "Scopes cannot be empty, Please provide a scope";
7384
throw error;
7485
}
7586
try {
76-
const accessToken: string = await this.userAgentApplication.acquireTokenSilent(this.scopes);
87+
const accessToken: string = await this.userAgentApplication.acquireTokenSilent(scopes);
7788
return accessToken;
7889
} catch (errorMsg) {
7990
try {
80-
const idToken: string = await this.userAgentApplication.loginPopup(this.scopes);
91+
const idToken: string = await this.userAgentApplication.loginPopup(scopes);
8192
try {
82-
const accessToken: string = await this.userAgentApplication.acquireTokenSilent(this.scopes);
93+
const accessToken: string = await this.userAgentApplication.acquireTokenSilent(scopes);
8394
return accessToken;
8495
} catch (error) {
85-
const accessToken: string = await this.userAgentApplication.acquireTokenPopup(this.scopes);
96+
const accessToken: string = await this.userAgentApplication.acquireTokenPopup(scopes);
8697
return accessToken;
8798
}
8899
} catch (errorMsg) {

src/middleware/AuthenticationHandler.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@
1010
*/
1111

1212
import { AuthenticationProvider } from "../IAuthenticationProvider";
13+
import { AuthenticationProviderOptions } from "../IAuthenticationProviderOptions";
1314
import { Context } from "../IContext";
1415

1516
import { Middleware } from "./IMiddleware";
17+
import { MiddlewareControl } from "./MiddlewareControl";
1618
import { setRequestHeader } from "./MiddlewareUtil";
19+
import { AuthenticationHandlerOptions } from "./options/AuthenticationHandlerOptions";
1720

1821
/**
1922
* @class
@@ -31,7 +34,7 @@ export class AuthenticationHandler implements Middleware {
3134
* @private
3235
* A member to hold an AuthenticationProvider instance
3336
*/
34-
private authProvider: AuthenticationProvider;
37+
private authenticationProvider: AuthenticationProvider;
3538

3639
/**
3740
* @private
@@ -43,23 +46,36 @@ export class AuthenticationHandler implements Middleware {
4346
* @public
4447
* @constructor
4548
* Creates an instance of AuthenticationHandler
46-
* @param {AuthenticationProvider} authProvider - The authentication provider for the authentication handler
49+
* @param {AuthenticationProvider} authenticationProvider - The authentication provider for the authentication handler
4750
*/
48-
public constructor(authProvider: AuthenticationProvider) {
49-
this.authProvider = authProvider;
51+
public constructor(authenticationProvider: AuthenticationProvider) {
52+
this.authenticationProvider = authenticationProvider;
5053
}
5154

5255
/**
5356
* @public
5457
* @async
5558
* To execute the current middleware
56-
* @param {context} context - The context object of the request
59+
* @param {Context} context - The context object of the request
5760
* @returns A Promise that resolves to nothing
5861
*/
5962
public async execute(context: Context): Promise<void> {
6063
try {
61-
const token = await this.authProvider.getAccessToken();
62-
const bearerKey = `Bearer ${token}`;
64+
let options: AuthenticationHandlerOptions;
65+
if (context.middlewareControl instanceof MiddlewareControl) {
66+
options = context.middlewareControl.getMiddlewareOptions(AuthenticationHandler.name) as AuthenticationHandlerOptions;
67+
}
68+
let authenticationProvider: AuthenticationProvider;
69+
let authenticationProviderOptions: AuthenticationProviderOptions;
70+
if (typeof options !== "undefined") {
71+
authenticationProvider = options.authenticationProvider;
72+
authenticationProviderOptions = options.authenticationProviderOptions;
73+
}
74+
if (typeof authenticationProvider === "undefined") {
75+
authenticationProvider = this.authenticationProvider;
76+
}
77+
const token: string = await authenticationProvider.getAccessToken(authenticationProviderOptions);
78+
const bearerKey: string = `Bearer ${token}`;
6379
setRequestHeader(context.request, context.options, AuthenticationHandler.AUTHORIZATION_HEADER, bearerKey);
6480
return await this.nextMiddleware.execute(context);
6581
} catch (error) {

0 commit comments

Comments
 (0)