Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
06a744b
Initial Commit
tnorling May 15, 2020
f6fefcd
Create clientInfo from idToken
tnorling May 15, 2020
69e40cb
Merge branch 'cloud-discovery' of https://github.com/AzureAD/microsof…
tnorling May 27, 2020
56fdfdd
Update default type
tnorling May 27, 2020
10335de
Update Sample Readmes
tnorling May 27, 2020
520a465
Update package name for sample
tnorling May 27, 2020
c2ccdec
Merge branch 'cloud-discovery' of https://github.com/AzureAD/microsof…
tnorling Jun 3, 2020
00873a3
Merge branch 'dev' of https://github.com/AzureAD/microsoft-authentica…
tnorling Jun 3, 2020
167ca67
Merge branch 'dev' of https://github.com/AzureAD/microsoft-authentica…
tnorling Jun 15, 2020
47d0a87
Update AuthorityType logic
tnorling Jun 15, 2020
336fc2a
Remove sample
tnorling Jun 15, 2020
c88a12e
Move isAdfs to Authority class
tnorling Jun 15, 2020
661f000
Unit tests
tnorling Jun 15, 2020
3b9c058
Add tests
tnorling Jun 16, 2020
5197bc4
Add upn as backup for username
tnorling Jun 16, 2020
76b1685
Revert "Add upn as backup for username"
tnorling Jun 16, 2020
c969187
Add upn as backup for username
tnorling Jun 16, 2020
5a5472b
Address Feedback
tnorling Jun 16, 2020
5398cca
Update to ternary
tnorling Jun 16, 2020
dfa6f5d
Update lib/msal-core/src/ClientInfo.ts
tnorling Jun 17, 2020
9b29939
Merge branch 'dev' into msal-core-adfs
tnorling Jun 17, 2020
c1b8d1a
Merge branch 'dev' of https://github.com/AzureAD/microsoft-authentica…
tnorling Jul 7, 2020
4a664b9
Fix linting
tnorling Jul 7, 2020
176334f
Merge branch 'dev' into msal-core-adfs
tnorling Jul 25, 2020
553a623
Merge branch 'dev' into msal-core-adfs
tnorling Aug 11, 2020
63bac81
Change files
tnorling Aug 12, 2020
c08165c
Merge branch 'dev' of https://github.com/AzureAD/microsoft-authentica…
tnorling Aug 12, 2020
c400722
Merge branch 'dev' into msal-core-adfs
tnorling Aug 17, 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
46 changes: 46 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: "Code Scanning - Action"

on:
push:
schedule:
- cron: '0 0 * * 0'

jobs:
CodeQL-Build:

strategy:
fail-fast: false


# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below).
- name: Autobuild
uses: github/codeql-action/autobuild@v1

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
28 changes: 17 additions & 11 deletions lib/msal-browser/src/app/PublicClientApplication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@
*/
import {
Account,
SPAClient,
AuthenticationParameters,
Authority,
AuthorityFactory, ClientAuthError,
INetworkModule,
TokenResponse,
UrlString,
TemporaryCacheKeys,
TokenRenewParameters,
StringUtils,
PromptValue,
ServerError,
Authority,
AuthorityFactory,
InteractionRequiredAuthError,
B2cAuthority
SPAClient,
StringUtils,
TemporaryCacheKeys,
TokenRenewParameters,
TokenResponse,
UrlString,
AuthorityType,
B2cAuthority,
InteractionRequiredAuthError
} from "@azure/msal-common";
import { Configuration, buildConfiguration } from "../config/Configuration";
import { buildConfiguration, Configuration } from "../config/Configuration";
import { BrowserStorage } from "../cache/BrowserStorage";
import { CryptoOps } from "../crypto/CryptoOps";
import { RedirectHandler } from "../interaction_handler/RedirectHandler";
Expand Down Expand Up @@ -100,6 +101,11 @@ export class PublicClientApplication {
this.config.system.networkClient
);

// This is temporary. Remove when ADFS is supported for browser
if(this.defaultAuthorityInstance.authorityType === AuthorityType.Adfs){
throw ClientAuthError.createInvalidAuthorityTypeError(this.defaultAuthorityInstance.canonicalAuthority);
}

// Create auth module.
this.authModule = new SPAClient({
authOptions: {
Expand Down
57 changes: 50 additions & 7 deletions lib/msal-browser/test/client/PublicClientApplication.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,42 @@
import * as Mocha from "mocha";
import chai from "chai";
import chaiAsPromised from "chai-as-promised";

chai.use(chaiAsPromised);
const expect = chai.expect;
import { PublicClientApplication } from "../../src/app/PublicClientApplication";
import { TEST_CONFIG, TEST_URIS, TEST_HASHES, TEST_TOKENS, TEST_DATA_CLIENT_INFO, TEST_TOKEN_LIFETIMES, RANDOM_TEST_GUID, DEFAULT_OPENID_CONFIG_RESPONSE, testNavUrl, testLogoutUrl } from "../utils/StringConstants";
import { AuthError, ServerError, AuthResponse, LogLevel, Constants, TemporaryCacheKeys, TokenResponse, Account, TokenExchangeParameters, IdTokenClaims, SPAClient, PromptValue, AuthenticationParameters } from "@azure/msal-common";
import {
TEST_CONFIG,
TEST_URIS,
TEST_HASHES,
TEST_TOKENS,
TEST_DATA_CLIENT_INFO,
TEST_TOKEN_LIFETIMES,
RANDOM_TEST_GUID,
DEFAULT_OPENID_CONFIG_RESPONSE,
testNavUrl,
testLogoutUrl
} from "../utils/StringConstants";
import {
AuthError,
ServerError,
AuthResponse,
LogLevel,
Constants,
TemporaryCacheKeys,
TokenResponse,
Account,
TokenExchangeParameters,
IdTokenClaims,
SPAClient,
PromptValue,
AuthenticationParameters, ClientAuthError, ClientAuthErrorMessage
} from "@azure/msal-common";
import { AuthCallback } from "../../src/types/AuthCallback";
import { BrowserConfigurationAuthErrorMessage, BrowserConfigurationAuthError } from "../../src/error/BrowserConfigurationAuthError";
import {
BrowserConfigurationAuthErrorMessage,
BrowserConfigurationAuthError
} from "../../src/error/BrowserConfigurationAuthError";
import sinon from "sinon";
import { BrowserUtils } from "../../src/utils/BrowserUtils";
import { BrowserConstants } from "../../src/utils/BrowserConstants";
Expand Down Expand Up @@ -74,6 +103,20 @@ describe("PublicClientApplication.ts Class Unit Tests", () => {
});
expect(window.sessionStorage.getItem(`${Constants.CACHE_PREFIX}.${TEST_CONFIG.MSAL_CLIENT_ID}.${TemporaryCacheKeys.URL_HASH}`)).to.be.eq(TEST_HASHES.TEST_SUCCESS_CODE_HASH);
});

it("ADFS authority throws error", () => {

expect(() =>{
new PublicClientApplication({
auth: {
clientId: TEST_CONFIG.MSAL_CLIENT_ID,
authority: TEST_CONFIG.ADFS_AUTHORITY
}
});

}).to.throw(ClientAuthErrorMessage.invalidAuthorityType.desc);

});
});

describe("Redirect Flow Unit tests", () => {
Expand Down Expand Up @@ -110,7 +153,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => {
const testServerTokenResponse = {
headers: null,
status: 200,
body : {
body: {
token_type: TEST_CONFIG.TOKEN_TYPE_BEARER,
scope: TEST_CONFIG.DEFAULT_SCOPES.join(" "),
expires_in: TEST_TOKEN_LIFETIMES.DEFAULT_EXPIRES_IN,
Expand Down Expand Up @@ -213,7 +256,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => {
const testServerTokenResponse = {
headers: null,
status: 200,
body : {
body: {
token_type: TEST_CONFIG.TOKEN_TYPE_BEARER,
scope: TEST_CONFIG.DEFAULT_SCOPES.join(" "),
expires_in: TEST_TOKEN_LIFETIMES.DEFAULT_EXPIRES_IN,
Expand Down Expand Up @@ -561,7 +604,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => {
refreshToken: testServerTokenResponse.refresh_token,
expiresOn: new Date(Date.now() + (testServerTokenResponse.expires_in * 1000)),
account: testAccount,
userRequestState: ""
userRequestState: ""
};
sinon.stub(SPAClient.prototype, "createLoginUrl").resolves(testNavUrl);
const loadFrameSyncSpy = sinon.spy(SilentHandler.prototype, <any>"loadFrameSync");
Expand Down Expand Up @@ -666,7 +709,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => {
refreshToken: testServerTokenResponse.refresh_token,
expiresOn: new Date(Date.now() + (testServerTokenResponse.expires_in * 1000)),
account: testAccount,
userRequestState: ""
userRequestState: ""
};
const createAcqTokenStub = sinon.stub(SPAClient.prototype, "createAcquireTokenUrl").resolves(testNavUrl);
const silentTokenHelperStub = sinon.stub(pca, <any>"silentTokenHelper").resolves(testTokenResponse);
Expand Down
1 change: 1 addition & 0 deletions lib/msal-browser/test/utils/StringConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const TEST_CONFIG = {
MSAL_TENANT_ID: "3338040d-6c67-4c5b-b112-36a304b66dad",
validAuthority: TEST_URIS.DEFAULT_INSTANCE + "common",
alternateValidAuthority: TEST_URIS.ALTERNATE_INSTANCE + "common",
ADFS_AUTHORITY: "https://authority.com/adfs",
applicationName: "msal.js-tests",
applicationVersion: "msal.js-tests.1.0.fake",
STATE: "1234",
Expand Down
7 changes: 7 additions & 0 deletions lib/msal-common/docs/ADFS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ADFS Support

MSAL supports connecting to Azure AD, which signs in managed-users (users managed in Azure AD) or federated users (users managed by another identity provider such as ADFS). MSAL does not differentiate between these two types of users. As far as it’s concerned, it talks to Azure AD. The authority that you would pass in this case is the normal Azure AD Authority: `https://login.microsoftonline.com/{Enter_the_Tenant_Info_Here}`

MSAL also supports directly connection to AD FS 2019, which is Open ID Connect compliant and has support scopes and PKCE. This support requires that a service pack [KB 4490481](https://support.microsoft.com/en-us/help/4490481/windows-10-update-kb4490481) is applied to Windows Server. When connecting directly to AD FS, the authority you'll want to use to build your application will be of form `https://mysite.contoso.com/adfs/`

Currently, there are no plans to support a direct connection to ADFS 16 or ADFS v2. ADFS 16 does not support scopes, and ADFS v2 is not OIDC compliant.
32 changes: 32 additions & 0 deletions lib/msal-common/src/authority/AdfsAuthority.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import { Authority } from "./Authority";
import { AuthorityType } from "./AuthorityType";
import { INetworkModule } from "../network/INetworkModule";

/**
* The AdfsAuthority class extends the Authority class and adds functionality specific to ADFS 2019
*/
export class AdfsAuthority extends Authority {

/**
* Return authority type
*/
public get authorityType(): AuthorityType {
return AuthorityType.Adfs;
}

public constructor(authority: string, networkInterface: INetworkModule) {
super(authority, networkInterface);
}

/**
* Returns a promise which resolves to the OIDC endpoint
*/
public async getOpenIdConfigurationEndpointAsync(): Promise<string> {
return `${this.canonicalAuthority}.well-known/openid-configuration`;
}
}
8 changes: 8 additions & 0 deletions lib/msal-common/src/authority/Authority.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ export abstract class Authority {
}
}

public get deviceCodeEndpoint(): string {
if(this.discoveryComplete()) {
return this.tenantDiscoveryResponse.token_endpoint.replace("/token", "/devicecode");
} else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
}

/**
* OAuth logout endpoint for requests
*/
Expand Down
4 changes: 3 additions & 1 deletion lib/msal-common/src/authority/AuthorityFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { INetworkModule } from "./../network/INetworkModule";
import { StringUtils } from "./../utils/StringUtils";
import { UrlString } from "./../url/UrlString";
import { Constants } from "../utils/Constants";
import { AdfsAuthority } from "./AdfsAuthority";

export class AuthorityFactory {

Expand Down Expand Up @@ -50,7 +51,8 @@ export class AuthorityFactory {
return new AadAuthority(authorityUrl, networkInterface);
case AuthorityType.B2C:
return new B2cAuthority(authorityUrl, networkInterface);
// TODO: Support ADFS here in a later PR
case AuthorityType.Adfs:
return new AdfsAuthority(authorityUrl, networkInterface);
default:
throw ClientAuthError.createInvalidAuthorityTypeError(`${authorityUrl}`);
}
Expand Down
4 changes: 3 additions & 1 deletion lib/msal-common/src/client/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Logger } from "../logger/Logger";
import { AADServerParamKeys, Constants, HeaderNames } from "../utils/Constants";
import { NetworkResponse } from "../network/NetworkManager";
import { ServerAuthorizationTokenResponse } from "../server/ServerAuthorizationTokenResponse";
import { B2cAuthority } from "../authority/B2cAuthority";
import { UnifiedCacheManager } from "../unifiedCache/UnifiedCacheManager";

/**
Expand Down Expand Up @@ -70,7 +71,8 @@ export abstract class BaseClient {
// Set the network interface
this.networkClient = this.config.networkInterface;

// Default authority instance.
B2cAuthority.setKnownAuthorities(this.config.authOptions.knownAuthorities);

this.defaultAuthority = this.config.authOptions.authority;
}

Expand Down
32 changes: 15 additions & 17 deletions lib/msal-common/src/client/DeviceCodeClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,22 @@ export class DeviceCodeClient extends BaseClient {
*/
private async getDeviceCode(request: DeviceCodeRequest): Promise<DeviceCodeResponse> {

const deviceCodeUrl = this.createDeviceCodeUrl(request);
const queryString = this.createQueryString(request);
const headers = this.createDefaultLibraryHeaders();

return this.executeGetRequestToDeviceCodeEndpoint(deviceCodeUrl, headers);
return this.executePostRequestToDeviceCodeEndpoint(this.defaultAuthority.deviceCodeEndpoint, queryString, headers);
}

/**
* Executes GET request to device code endpoint
* @param deviceCodeUrl
* Executes POST request to device code endpoint
* @param deviceCodeEndpoint
* @param queryString
* @param headers
*/
private async executeGetRequestToDeviceCodeEndpoint(deviceCodeUrl: string, headers: Map<string, string>): Promise<DeviceCodeResponse> {
private async executePostRequestToDeviceCodeEndpoint(
deviceCodeEndpoint: string,
queryString: string,
headers: Map<string, string>): Promise<DeviceCodeResponse> {

const {
body: {
Expand All @@ -68,7 +72,12 @@ export class DeviceCodeClient extends BaseClient {
interval,
message
}
} = await this.networkClient.sendGetRequestAsync<ServerDeviceCodeResponse>(deviceCodeUrl, {headers});
} = await this.networkClient.sendPostRequestAsync<ServerDeviceCodeResponse>(
deviceCodeEndpoint,
{
body: queryString,
headers: headers
});

return {
userCode,
Expand All @@ -80,17 +89,6 @@ export class DeviceCodeClient extends BaseClient {
};
}

/**
* Create device code endpoint url
* @param request
*/
private createDeviceCodeUrl(request: DeviceCodeRequest): string {
const queryString: string = this.createQueryString(request);

// TODO add device code endpoint to authority class
return `${this.defaultAuthority.canonicalAuthority}${Constants.DEVICE_CODE_ENDPOINT_PATH}?${queryString}`;
}

/**
* Create device code endpoint query parameters and returns string
*/
Expand Down
2 changes: 1 addition & 1 deletion lib/msal-common/src/client/RefreshTokenClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class RefreshTokenClient extends BaseClient {

const scopeSet = new ScopeSet(request.scopes || [],
this.config.authOptions.clientId,
true);
false);
parameterBuilder.addScopes(scopeSet);
parameterBuilder.addClientId(this.config.authOptions.clientId);
parameterBuilder.addGrantType(GrantType.REFRESH_TOKEN_GRANT);
Expand Down
Loading