Skip to content
This repository was archived by the owner on May 3, 2024. It is now read-only.

Commit 3c31231

Browse files
committed
add code annotations
1 parent 28315c9 commit 3c31231

File tree

8 files changed

+41
-19
lines changed

8 files changed

+41
-19
lines changed

6-AdvancedScenarios/3-call-api-acrs/API/app.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License.
4+
*/
5+
16
const express = require('express');
27
const session = require('express-session');
38
const methodOverride = require('method-override');
@@ -30,7 +35,7 @@ app.use(express.json());
3035

3136
/**
3237
* We need to enable CORS for client's domain in order to
33-
* expose www-authenticate header in response from web API
38+
* expose www-authenticate header in response from the web API
3439
*/
3540
app.use(cors({
3641
origin: process.env.CORS_ALLOWED_DOMAINS, // replace with client domain

6-AdvancedScenarios/3-call-api-acrs/API/controllers/adminController.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,24 +57,23 @@ exports.postDashboardPage = async(req, res, next) => {
5757
// check if acrs is empty
5858
if (acrs.value.length === 0) {
5959

60-
// create
6160
defaultAcrsList = [
6261
{
6362
id: 'c1',
6463
displayName: 'Require strong authentication',
65-
description: 'Require strong authentication',
64+
description: 'User needs to perform multifactor authentication',
6665
isAvailable: true
6766
},
6867
{
6968
id: 'c2',
7069
displayName: 'Require compliant devices',
71-
description: 'Require compliant devices',
70+
description: 'Users needs to prove using a compliant device',
7271
isAvailable: true
7372
},
7473
{
7574
id: 'c3',
7675
displayName: 'Require trusted locations',
77-
description: 'Require trusted locations',
76+
description: 'User needs to prove connecting from a trusted location',
7877
isAvailable: true
7978
},
8079
]

6-AdvancedScenarios/3-call-api-acrs/API/routes/adminRoutes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module.exports = (authProvider) => {
1414
router.get('/signin', authProvider.signIn({ successRedirect: '/admin' }));
1515
router.get('/signout', authProvider.signOut({ successRedirect: '/admin' }));
1616

17+
// check if user is authenticated, then obtain an access token for the specified resource
1718
router.get(
1819
'/dashboard',
1920
authProvider.isAuthenticated(),

6-AdvancedScenarios/3-call-api-acrs/API/utils/claimsManager.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
const authConfig = require('../.env');
2-
1+
/**
2+
* This custom middleware inspects the incoming request for client capabilities and auth context
3+
* @param {string} authContextId
4+
*/
35
const checkForRequiredAuthContext = (req, res, next, authContextId) => {
46
if (!req.authInfo['acrs'] || !req.authInfo['acrs'].includes(authContextId)) {
57
if (isClientCapableOfClaimsChallenge(req.authInfo)) {
@@ -18,6 +20,11 @@ const checkForRequiredAuthContext = (req, res, next, authContextId) => {
1820
}
1921
}
2022

23+
/**
24+
* xms_cc claim in the access token indicates that the client app of user is capable of
25+
* handling claims challenges. See for more: https://docs.microsoft.com/en-us/azure/active-directory/develop/claims-challenge#client-capabilities
26+
* @param {Object} accessTokenClaims:
27+
*/
2128
const isClientCapableOfClaimsChallenge = (accessTokenClaims) => {
2229
if (accessTokenClaims['xms_cc'] && accessTokenClaims['xms_cc'].includes('CP1')) {
2330
return true;
@@ -26,13 +33,19 @@ const isClientCapableOfClaimsChallenge = (accessTokenClaims) => {
2633
return false;
2734
}
2835

36+
/**
37+
* Generates www-authenticate header and claims challenge for a given authentication context id. For more information, see:
38+
* https://docs.microsoft.com/en-us/azure/active-directory/develop/claims-challenge#claims-challenge-header-format
39+
*/
2940
const generateClaimsChallenge = (authContextId) => {
3041
const clientId = process.env.CLIENT_ID;
3142

3243
const statusCode = 401;
3344

45+
// claims challenge object
3446
const challenge = { access_token: { acrs: { essential: true, value: authContextId }}};
3547

48+
// base64 encode the challenge object
3649
const base64str = Buffer.from(JSON.stringify(challenge)).toString('base64');
3750
const headers = ["www-authenticate", "Bearer realm=\"\", authorization_uri=\"https://login.microsoftonline.com/common/oauth2/v2.0/authorize\", client_id=\"" + clientId + "\", error=\"insufficient_claims\", claims=\"" + base64str + "\", cc_type=\"authcontext\""];
3851
const message = "The presented access tokens had insufficient claims. Please request for claims designated in the www-authentication header and try again.";

6-AdvancedScenarios/3-call-api-acrs/API/utils/routeGuard.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@ const AuthContext = require('../models/authContext');
44
const authContextGuard = (req, res, next) => {
55
const acrs = AuthContext.getAuthContexts();
66

7+
// if there is no auth context in the db, let the request through
78
if (acrs.length === 0) {
89
return next();
910
} else {
1011
const authContext = acrs.find(ac => ac.operation === req.method && ac.tenantId === req.authInfo.tid);
1112

1213
if (authContext) {
14+
// if found, check the request for the required claims
1315
return checkForRequiredAuthContext(req, res, next, authContext.authContextId);
1416
}
1517

16-
return next();
18+
next();
1719
}
1820
}
1921

6-AdvancedScenarios/3-call-api-acrs/SPA/src/authConfig.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
/*
2-
* Copyright (c) Microsoft Corporation. All rights reserved.
3-
* Licensed under the MIT License.
4-
*/
5-
61
import { LogLevel } from "@azure/msal-browser";
72

83
/**

6-AdvancedScenarios/3-call-api-acrs/SPA/src/fetch.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
/*
2-
* Copyright (c) Microsoft Corporation. All rights reserved.
3-
* Licensed under the MIT License.
4-
*/
5-
61
import { BrowserAuthError } from "@azure/msal-browser";
72
import { protectedResources } from "./authConfig";
83
import { msalInstance } from "./index";
@@ -22,6 +17,13 @@ const getToken = async () => {
2217
return response.accessToken;
2318
}
2419

20+
/**
21+
* This method inspects the HTTP response from a fetch call for the "www-authenticate header"
22+
* If present, it grabs the claims challenge from the header, then uses msal to ask Azure AD for a new access token containing the needed claims
23+
* If not present, then it simply returns the response as json
24+
* For more information, visit: https://docs.microsoft.com/en-us/azure/active-directory/develop/claims-challenge#claims-challenge-header-format
25+
* @param {Object} response: HTTP response
26+
*/
2527
const handleClaimsChallenge = async (response) => {
2628
if (response.status === 401) {
2729
if (response.headers.get('www-authenticate')) {
@@ -32,7 +34,7 @@ const handleClaimsChallenge = async (response) => {
3234

3335
try {
3436
await msalInstance.acquireTokenPopup({
35-
claims: window.atob(claimsChallenge),
37+
claims: window.atob(claimsChallenge), // decode the base64 string
3638
scopes: protectedResources.apiTodoList.scopes
3739
});
3840
} catch (error) {

6-AdvancedScenarios/3-call-api-acrs/SPA/src/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License.
4+
*/
5+
16
import React from "react";
27
import ReactDOM from "react-dom";
38

0 commit comments

Comments
 (0)