Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
update browser and add documentation
  • Loading branch information
Santiago Gonzalez committed May 15, 2020
commit 65985ed7fe57f408dc35edc69bc3f4634611596d
24 changes: 15 additions & 9 deletions lib/msal-browser/src/app/PublicClientApplication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@
*/
import {
Account,
SPAClient,
AuthenticationParameters,
Authority,
AuthorityFactory, ClientAuthError,
INetworkModule,
TokenResponse,
UrlString,
TemporaryCacheKeys,
TokenRenewParameters,
StringUtils,
PromptValue,
ServerError,
Authority,
AuthorityFactory,
SPAClient,
StringUtils,
TemporaryCacheKeys,
TokenRenewParameters,
TokenResponse,
UrlString,
AuthorityType
} 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 @@ -95,6 +96,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.
25 changes: 25 additions & 0 deletions lib/msal-common/src/client/SPAClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { StringUtils } from "../utils/StringUtils";
import { UrlString } from "../url/UrlString";
import { Account } from "../account/Account";
import { buildClientInfo } from "../account/ClientInfo";
import { AuthorityType } from "../authority/AuthorityType";

/**
* SPAClient class
Expand Down Expand Up @@ -67,6 +68,12 @@ export class SPAClient extends BaseClient {
private async createUrl(request: AuthenticationParameters, isLoginCall: boolean): Promise<string> {
// Initialize authority or use default, and perform discovery endpoint check.
const acquireTokenAuthority = (request && request.authority) ? AuthorityFactory.createInstance(request.authority, this.networkClient) : this.defaultAuthority;

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

try {
await acquireTokenAuthority.resolveEndpointsAsync();
} catch (e) {
Expand Down Expand Up @@ -143,6 +150,12 @@ export class SPAClient extends BaseClient {

// Initialize authority or use default, and perform discovery endpoint check.
const acquireTokenAuthority = (tokenRequest && tokenRequest.authority) ? AuthorityFactory.createInstance(tokenRequest.authority, this.networkClient) : this.defaultAuthority;

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

if (!acquireTokenAuthority.discoveryComplete()) {
try {
await acquireTokenAuthority.resolveEndpointsAsync();
Expand Down Expand Up @@ -199,6 +212,12 @@ export class SPAClient extends BaseClient {

// Initialize authority or use default, and perform discovery endpoint check.
const acquireTokenAuthority = request.authority ? AuthorityFactory.createInstance(request.authority, this.networkClient) : this.defaultAuthority;

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

if (!acquireTokenAuthority.discoveryComplete()) {
try {
await acquireTokenAuthority.resolveEndpointsAsync();
Expand Down Expand Up @@ -271,6 +290,12 @@ export class SPAClient extends BaseClient {

// Acquire token authorities.
const acquireTokenAuthority = (authorityUri) ? AuthorityFactory.createInstance(authorityUri, this.networkClient) : this.defaultAuthority;

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

if (!acquireTokenAuthority.discoveryComplete()) {
try {
await acquireTokenAuthority.resolveEndpointsAsync();
Expand Down
1 change: 1 addition & 0 deletions lib/msal-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export { IdTokenClaims } from "./account/IdTokenClaims";
// Authority
export { Authority } from "./authority/Authority";
export { AuthorityFactory } from "./authority/AuthorityFactory";
export { AuthorityType } from "./authority/AuthorityType";
// Cache
export { ICacheStorage } from "./cache/ICacheStorage";
// Network Interface
Expand Down
1 change: 1 addition & 0 deletions samples/msal-node-auth-code/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function redirectToAzureAd(req, res){
const authCodeUrlParameters = {
scopes: ["user.read"],
redirectUri: ["http://localhost:3000/redirect"],
prompt: msal.Prompt.SELECT_ACCOUNT
};

pca.getAuthCodeUrl(authCodeUrlParameters)
Expand Down