UNPKG

passport-azure-ad

Version:

OIDC and Bearer Passport strategies for Azure Active Directory

317 lines (258 loc) 13.1 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'; /****************************************************************************** * Testing tools setup *****************************************************************************/ var chromedriver = require('./driver'); var service = chromedriver.get_service(); var error_handler = chromedriver.error_handler; var webdriver = chromedriver.webdriver; var By = webdriver.By; var until = webdriver.until; var chai = require('chai'); var expect = chai.expect; const TEST_TIMEOUT = 1000000; // 1000 seconds const LOGIN_WAITING_TIME = 1000; // 1 second /****************************************************************************** * configurations needed *****************************************************************************/ var test_parameters = {}; var client_config = {}; var server_config, server_config_with_req, server_config_allow_multiAud, server_config_wrong_issuer, server_config_wrong_identityMetadata, server_config_wrong_audience, server_config_wrong_issuer_no_validateIssuer, server_config_multiple_audience, server_config_common_endpoint, server_config_common_endpoint_with_req, server_config_common_endpoint_dynamic_tenant, server_config_common_endpoint_allow_multiAud, server_config_common_endpoint_wrong_issuer, server_config_common_endpoint_wrong_audience, server_config_common_endpoint_wrong_issuer_no_validateIssuer = {}; var driver; var client_already_logged_in = false; var client; /****************************************************************************** * Untility functions for the tests *****************************************************************************/ var get_test_parameters = (apply_test_parameters_callback, done) => { var is_test_parameters_completed = require('./test_parameters').is_test_parameters_completed; if (is_test_parameters_completed) { test_parameters = require('./test_parameters').test_parameters.v1_params; apply_test_parameters_callback(done); } else { require('./script').set_test_parameters((params) => { test_parameters = params.v1_params; apply_test_parameters_callback(done); }); } }; var apply_test_parameters = (done) => { client_config = { identityMetadata: 'https://login.microsoftonline.com/' + test_parameters.tenantID + '/.well-known/openid-configuration', clientID: test_parameters.clientID, responseType: 'code id_token', responseMode: 'form_post', redirectUrl: 'http://localhost:3000/auth/openid/return', allowHttpForRedirectUrl: true, clientSecret: test_parameters.clientSecret, validateIssuer: true, issuer: ['https://sts.windows.net/' + test_parameters.tenantID + '/'], passReqToCallback: false, scope: null, loggingLevel: null, nonceLifetime: null, }; server_config = { identityMetadata: 'https://login.microsoftonline.com/' + test_parameters.tenantID + '/.well-known/openid-configuration', clientID: test_parameters.clientID, validateIssuer: true, passReqToCallback: false, issuer: null, audience: null, // passport is expected to use clientID by default if audience is not provided allowMultiAudiencesInToken: false, loggingLevel: null, }; server_config_with_req = JSON.parse(JSON.stringify(server_config)); server_config_with_req.passReqToCallback = true; server_config_allow_multiAud = JSON.parse(JSON.stringify(server_config)); server_config_allow_multiAud.allowMultiAudiencesInToken = false; server_config_wrong_issuer = JSON.parse(JSON.stringify(server_config)); server_config_wrong_issuer.issuer = 'wrong_issuer'; server_config_wrong_identityMetadata = JSON.parse(JSON.stringify(server_config)); server_config_wrong_identityMetadata.identityMetadata = 'https://login.microsoftonline.com/wrongTenant/.well-known/openid-configuration'; server_config_wrong_audience = JSON.parse(JSON.stringify(server_config)); server_config_wrong_audience.audience = 'wrong_audience'; server_config_wrong_issuer_no_validateIssuer = JSON.parse(JSON.stringify(server_config)); server_config_wrong_issuer_no_validateIssuer.issuer = 'wrong_issuer'; server_config_wrong_issuer_no_validateIssuer.validateIssuer = false; server_config_multiple_audience = JSON.parse(JSON.stringify(server_config)); server_config_multiple_audience.audience = ['https://graph.windows.net', test_parameters.clientID]; server_config_common_endpoint = JSON.parse(JSON.stringify(server_config)); server_config_common_endpoint.identityMetadata = 'https://login.microsoftonline.com/common/.well-known/openid-configuration'; server_config_common_endpoint.issuer = 'https://sts.windows.net/' + test_parameters.tenantID + '/'; server_config_common_endpoint_dynamic_tenant = JSON.parse(JSON.stringify(server_config)); server_config_common_endpoint_dynamic_tenant.identityMetadata = 'https://login.microsoftonline.com/common/.well-known/openid-configuration'; server_config_common_endpoint_dynamic_tenant.tenantIdOrName = test_parameters.tenantID; server_config_common_endpoint_with_req = JSON.parse(JSON.stringify(server_config_common_endpoint)); server_config_common_endpoint_with_req.passReqToCallback = true; server_config_common_endpoint_allow_multiAud = JSON.parse(JSON.stringify(server_config_common_endpoint)); server_config_common_endpoint_allow_multiAud.allowMultiAudiencesInToken = false; server_config_common_endpoint_wrong_issuer = JSON.parse(JSON.stringify(server_config_common_endpoint)); server_config_common_endpoint_wrong_issuer.issuer = 'wrong_issuer'; server_config_common_endpoint_wrong_audience = JSON.parse(JSON.stringify(server_config_common_endpoint)); server_config_common_endpoint_wrong_audience.audience = 'wrong_audience'; server_config_common_endpoint_wrong_issuer_no_validateIssuer = JSON.parse(JSON.stringify(server_config_common_endpoint)); server_config_common_endpoint_wrong_issuer_no_validateIssuer.issuer = 'wrong_issuer'; server_config_common_endpoint_wrong_issuer_no_validateIssuer.validateIssuer = false; done(); }; var get_token_for_resource = (resource, done) => { if (!driver) driver = chromedriver.get_driver(); client = require('./app/client_for_api')(client_config, { resourceURL: resource }); driver.get('http://localhost:3000') .then(() => { driver.wait(until.titleIs('Example'), 10000); driver.findElement(By.xpath('/html/body/p/a')).click(); }).then(() => { // we only need to enter the user name and password if we haven't logged in yet if (!client_already_logged_in) { driver.wait(until.titleIs('Sign in to your account'), 10000); var usernamebox = driver.findElement(By.name('loginfmt')); usernamebox.sendKeys(test_parameters.username); usernamebox.sendKeys(webdriver.Key.ENTER); var passwordbox = driver.findElement(By.name('passwd')); passwordbox.sendKeys(test_parameters.password); driver.sleep(LOGIN_WAITING_TIME); passwordbox = driver.findElement(By.name('passwd')); passwordbox.sendKeys(webdriver.Key.ENTER); client_already_logged_in = true; } }).then(() => { driver.wait(until.titleIs('Sign in to your account'), 5000).then( ()=>{ driver.findElement(By.id('idBtn_Back')).click().then(()=>{done();}); }, ()=>{ done();} ); }); }; var checkResult = (test_app_config, result, done) => { var server = require('./app/api')(test_app_config); driver.get('http://localhost:3000/callApi') .then(() => { driver.wait(until.titleIs('result'), 10000).catch((ex) => { error_handler(ex, server, done); }); driver.findElement(By.id('status')).getText().then((text) => { expect(text).to.equal(result); server.shutdown(done); }).catch((ex) => { error_handler(ex, server, done); }); }); }; /****************************************************************************** * The test cases *****************************************************************************/ describe('bearer test', function() { this.timeout(TEST_TIMEOUT); it('get and apply config', function(done) { get_test_parameters(apply_test_parameters, done); }); it('get token for the client itself', function(done) { get_token_for_resource(test_parameters.clientID, done); }); /****************************************************************************** * tenant specific endpoint *****************************************************************************/ it('should succeed', function(done) { checkResult(server_config, 'succeeded', done); }); it('should succeed', function(done) { checkResult(server_config_with_req, 'succeeded', done); }); it('should succeed', function(done) { checkResult(server_config_allow_multiAud, 'succeeded', done); }); it('should succeed', function(done) { checkResult(server_config_wrong_issuer_no_validateIssuer, 'succeeded', done); }); it('should fail with wrong audience', function(done) { checkResult(server_config_wrong_audience, 'Unauthorized', done); }); it('should fail with wrong issuer', function(done) { checkResult(server_config_wrong_issuer, 'Unauthorized', done); }); it('should fail with wrong identityMetadata', function(done) { checkResult(server_config_wrong_identityMetadata, 'Unauthorized', done); }); /****************************************************************************** * common endpoint *****************************************************************************/ it('should succeed', function(done) { checkResult(server_config_common_endpoint, 'succeeded', done); }); it('should succeed', function(done) { checkResult(server_config_common_endpoint_dynamic_tenant, 'succeeded', done); }); it('should succeed', function(done) { checkResult(server_config_common_endpoint_with_req, 'succeeded', done); }); it('should succeed', function(done) { checkResult(server_config_common_endpoint_allow_multiAud, 'succeeded', done); }); it('should succeed', function(done) { checkResult(server_config_wrong_issuer_no_validateIssuer, 'succeeded', done); }); it('should fail with wrong audience', function(done) { checkResult(server_config_common_endpoint_wrong_audience, 'Unauthorized', done); }); it('should fail with wrong issuer', function(done) { checkResult(server_config_common_endpoint_wrong_issuer, 'Unauthorized', done); }); /****************************************************************************** * test with multiple audiences in config *****************************************************************************/ // first test the token whose audience is itself (the clientID of this app) it('should succeed with multiple audience provided in config and access token for itself', function(done) { checkResult(server_config_multiple_audience, 'succeeded', done); }); // shut down the client which can get access_token for itself it('shutdown client', function(done) { expect('1').to.equal('1'); client.shutdown(done); }); // create a client which can get access_token for graph and generate an access_token it('get token for graph', function(done) { get_token_for_resource('https://graph.windows.net', done); }); it('should succeed with multiple audience provided in config and access token for graph', function(done) { checkResult(server_config_multiple_audience, 'succeeded', done); }); // clean up work it('close service', function(done) { expect('1').to.equal('1'); driver.quit(); service.stop(); client.shutdown(done); }); });