UNPKG

passport-azure-ad

Version:

OIDC and Bearer Passport strategies for Azure Active Directory

182 lines (151 loc) 9.32 kB
/** * Copyright (c) Microsoft Corporation * All Rights Reserved * MIT License * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the 'Software'), to deal in the Software * without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 'use strict'; /* eslint no-underscore-dangle: 0 */ var chai = require('chai'); var url = require('url'); chai.use(require('chai-passport-strategy')); const TEST_TIMEOUT = 1000000; // 1000 seconds var Metadata = require('../../lib/metadata').Metadata; var OIDCStrategy = require('../../lib/index').OIDCStrategy; var nonce = 'eDBXVqk40ng5BarS'; var id_token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlliUkFRUlljRV9tb3RXVkpLSHJ3TEJiZF85cyIsImtpZCI6IlliUkFRUlljRV9tb3RXVkpLSHJ3TEJiZF85cyJ9.eyJhdWQiOiIyYWJmM2E1Mi03ZDg2LTQ2MGItYTFlZi03N2RjNDNkZThhYWQiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8yNjhkYTFhMS05ZGI0LTQ4YjktYjFmZS02ODMyNTBiYTkwY2MvIiwiaWF0IjoxNDcxMzEzNDE3LCJuYmYiOjE0NzEzMTM0MTcsImV4cCI6MTQ3MTMxNzMxNywiYW1yIjpbInB3ZCJdLCJmYW1pbHlfbmFtZSI6Im9uZSIsImdpdmVuX25hbWUiOiJyb2JvdCIsImlwYWRkciI6IjE2Ny4yMjAuMC4xNjAiLCJuYW1lIjoicm9ib3QgMSIsIm5vbmNlIjoiZURCWFZxazQwbmc1QmFyUyIsIm9pZCI6Ijc5MTJmZTdiLWI1YWItNDI1Yi1iYjFmLTBlODNiOTlmY2E3ZiIsInB3ZF9leHAiOiI1ODQ2NzIiLCJwd2RfdXJsIjoiaHR0cHM6Ly9wb3J0YWwubWljcm9zb2Z0b25saW5lLmNvbS9DaGFuZ2VQYXNzd29yZC5hc3B4Iiwic3ViIjoiMUpNZHpPeEp5V2VDb2M1UXNZdkRQY29adHFodVdJWnhnbUhuQ3pRVFhhUSIsInRpZCI6IjI2OGRhMWExLTlkYjQtNDhiOS1iMWZlLTY4MzI1MGJhOTBjYyIsInVuaXF1ZV9uYW1lIjoicm9ib3RAc2lqdW4ub25taWNyb3NvZnQuY29tIiwidXBuIjoicm9ib3RAc2lqdW4ub25taWNyb3NvZnQuY29tIiwidmVyIjoiMS4wIn0.qoOyzkWJoB6XOOpISWamL6LrQ3VImbf5QWm5Zfs_dCgNpRaUS1EiOV8kijKZy4YTQ6ldKHhcbRtEAMZzrBl9k74Nks2JYSMAP05rAHvADyWcl89IzZ-cyWXwEfUJshRY8wMut11eBcIY3ml5--9AjtLYoqDKZZcNs2FdYsp9RwEc_tZWamHQ1rdknlbRDViXvqwtsNAgXLESA10nJIgwMEc6bKB3_pnEeBHjUJWcbKEeE6sZNdS66QK7DXEEnjEMdjShRZSULDX4pNtj-9azyNa8zKJPM4T-gkFkYO2LurKFRWTtjwshzxBCLXJ6cDq5B_kGcSJIMQ134Jbk7-kKiQ'; // change the last character in id_token to make a id_token with wrong signature var id_token_wrong_signature = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlliUkFRUlljRV9tb3RXVkpLSHJ3TEJiZF85cyIsImtpZCI6IlliUkFRUlljRV9tb3RXVkpLSHJ3TEJiZF85cyJ9.eyJhdWQiOiIyYWJmM2E1Mi03ZDg2LTQ2MGItYTFlZi03N2RjNDNkZThhYWQiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8yNjhkYTFhMS05ZGI0LTQ4YjktYjFmZS02ODMyNTBiYTkwY2MvIiwiaWF0IjoxNDcxMzEzNDE3LCJuYmYiOjE0NzEzMTM0MTcsImV4cCI6MTQ3MTMxNzMxNywiYW1yIjpbInB3ZCJdLCJmYW1pbHlfbmFtZSI6Im9uZSIsImdpdmVuX25hbWUiOiJyb2JvdCIsImlwYWRkciI6IjE2Ny4yMjAuMC4xNjAiLCJuYW1lIjoicm9ib3QgMSIsIm5vbmNlIjoiZURCWFZxazQwbmc1QmFyUyIsIm9pZCI6Ijc5MTJmZTdiLWI1YWItNDI1Yi1iYjFmLTBlODNiOTlmY2E3ZiIsInB3ZF9leHAiOiI1ODQ2NzIiLCJwd2RfdXJsIjoiaHR0cHM6Ly9wb3J0YWwubWljcm9zb2Z0b25saW5lLmNvbS9DaGFuZ2VQYXNzd29yZC5hc3B4Iiwic3ViIjoiMUpNZHpPeEp5V2VDb2M1UXNZdkRQY29adHFodVdJWnhnbUhuQ3pRVFhhUSIsInRpZCI6IjI2OGRhMWExLTlkYjQtNDhiOS1iMWZlLTY4MzI1MGJhOTBjYyIsInVuaXF1ZV9uYW1lIjoicm9ib3RAc2lqdW4ub25taWNyb3NvZnQuY29tIiwidXBuIjoicm9ib3RAc2lqdW4ub25taWNyb3NvZnQuY29tIiwidmVyIjoiMS4wIn0.qoOyzkWJoB6XOOpISWamL6LrQ3VImbf5QWm5Zfs_dCgNpRaUS1EiOV8kijKZy4YTQ6ldKHhcbRtEAMZzrBl9k74Nks2JYSMAP05rAHvADyWcl89IzZ-cyWXwEfUJshRY8wMut11eBcIY3ml5--9AjtLYoqDKZZcNs2FdYsp9RwEc_tZWamHQ1rdknlbRDViXvqwtsNAgXLESA10nJIgwMEc6bKB3_pnEeBHjUJWcbKEeE6sZNdS66QK7DXEEnjEMdjShRZSULDX4pNtj-9azyNa8zKJPM4T-gkFkYO2LurKFRWTtjwshzxBCLXJ6cDq5B_kGcSJIMQ134Jbk7-kKiq'; // Mock the process of getting PEMkey var PEMkey = "-----BEGIN RSA PUBLIC KEY-----\n\ MIIBCgKCAQEAvbcFrj193Gm6zeo5e2/y54Jx49sIgScv+2JO+n6NxNqQaKVnMkHc\n\ z+S1j2FfpFngotwGMzZIKVCY1SK8SKZMFfRTU3wvToZITwf3W1Qq6n+h+abqpyJT\n\ aqIcfhA0d6kEAM5NsQAKhfvw7fre1QicmU9LWVWUYAayLmiRX6o3tktJq6H58pUz\n\ Ttx/D0Dprnx6z5sW+uiMipLXbrgYmOez7htokJVgDg8w+yDFCxZNo7KVueUkLkxh\n\ NjYGkGfnt18s7ZW036WoTmdaQmW4CChf/o4TLE5VyGpYWm7I/+nV95BBvwlzokVV\n\ KzveKf3l5UU3c6PkGy+BB3E/ChqFm6sPWwIDAQAB\n\ -----END RSA PUBLIC KEY-----\n\ "; /* * test strategy (for response_type = 'id_token') which checks the expiration of id_token */ var options = { redirectUrl: 'https://localhost:3000/auth/openid/return', clientID: '2abf3a52-7d86-460b-a1ef-77dc43de8aad', identityMetadata: 'https://login.microsoftonline.com/sijun.onmicrosoft.com/.well-known/openid-configuration', responseType: 'id_token', responseMode: 'form_post', validateIssuer: true, passReqToCallback: false, sessionKey: 'my_key', issuer: 'https://sts.windows.net/268da1a1-9db4-48b9-b1fe-683250ba90cc/', }; var testStrategy = new OIDCStrategy(options, function(profile, done) { done(null, profile.upn); }); /* * Begin the testing */ var challenge; var user; var setIgnoreExpirationFalse = function(options) { options.ignoreExpiration = false; }; var setWrongIssuer = function(options) { options.issuer = ['wrong_issuer']; }; var rmValidateIssuer = function(options) { options.validateIssuer = undefined; }; var testPrepare = function(id_token_to_use, nonce_to_use, action) { return function(done) { // Mock `setOptions` testStrategy.setOptions = function(params, oauthConfig, optionsToValidate, done) { params.metadata.generateOidcPEM = () => { return PEMkey; }; optionsToValidate.validateIssuer = true; optionsToValidate.issuer = 'https://sts.windows.net/268da1a1-9db4-48b9-b1fe-683250ba90cc/'; optionsToValidate.audience = '2abf3a52-7d86-460b-a1ef-77dc43de8aad'; optionsToValidate.allowMultiAudiencesInToken = false; optionsToValidate.ignoreExpiration = true; optionsToValidate.algorithms = ['RS256']; optionsToValidate.nonce = nonce_to_use; optionsToValidate.clockSkew = testStrategy._options.clockSkew; if (action) { for (let i = 0; i < action.length; i++) action[i](optionsToValidate); } return done(); }; chai.passport .use(testStrategy) .fail(function(c) { challenge = c; done(); }) .success(function(u) { user = u; done(); }) .req(function(req) { // reset the value of challenge and user challenge = user = undefined; var time = Date.now(); // add state and nonce to session req.session = {'my_key': {'content': [{'state': 'my_state', 'nonce': nonce_to_use, 'policy': undefined, 'timeStamp': time}]}}; // add id_token and state to body req.body = {'id_token': id_token_to_use, 'state' : 'my_state'}; // empty query req.query = {}; }) .authenticate({}); }; }; describe('OIDCStrategy implicit flow test', function() { this.timeout(TEST_TIMEOUT); describe('should succeed without expiration checking', function() { before(testPrepare(id_token, nonce)); it('should succeed with expected user', function() { chai.expect(user).to.equal('robot@sijun.onmicrosoft.com'); }); }); describe('should fail for id_token with invalid signature', function() { before(testPrepare(id_token_wrong_signature, nonce)); it('should fail', function() { chai.expect(challenge).to.equal('In _validateResponse: invalid signature'); }); }); describe('should fail for id_token with wrong nonce', function() { before(testPrepare(id_token, 'wrong_nonce')); it('should fail', function() { chai.expect(challenge).to.equal('In _validateResponse: invalid nonce'); }); }); describe('should fail with id_token expiration checking', function() { before(testPrepare(id_token, nonce, [setIgnoreExpirationFalse])); it('should fail', function() { chai.expect(challenge).to.equal('In _validateResponse: jwt is expired'); }); }); describe('should fail with wrong issuer', function() { // we check the issuer by default before(testPrepare(id_token, nonce, [setWrongIssuer])); it('should fail', function() { chai.expect(challenge).to.equal('In _validateResponse: jwt issuer is invalid. expected: wrong_issuer'); }); }); describe('should fail with wrong issuer with default value of validateIssuer', function() { // for non-common endpoint, we force to validate issuer before(testPrepare(id_token, nonce, [rmValidateIssuer, setWrongIssuer])); it('should fail', function() { chai.expect(challenge).to.equal('In _validateResponse: jwt issuer is invalid. expected: wrong_issuer'); }); }); });