From c306c17e46c108ae680bd90829e8e98fb65416a1 Mon Sep 17 00:00:00 2001 From: Navya Canumalla Date: Thu, 8 Mar 2018 18:20:37 -0800 Subject: [PATCH 01/36] Add pii logging info to Readme --- README.md | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d1dc6fc7..9a718b06 100644 --- a/README.md +++ b/README.md @@ -236,13 +236,28 @@ Log levels are mapped as: 3: Verbose You can add the code below to app.js to turn on logging. Implement the `log` method depending on how you want to redirect logs. +```javascript +Logging = { + level: 3, + log: function (message) { + console.log(message); + }, + piiLoggingEnabled: false +}; +``` +#### Personal Identifiable Information (PII) & Organizational Identifiable Information (OII) + +By default, ADAL logging does not capture or log any PII or OII. The library allows app developers to turn this on by configuring the `piiLoggingEnabled` flag on the log context. By turning on PII or OII, the app takes responsibility for safely handling highly-sensitive data and complying with any regulatory requirements. + +```javascript +//PII or OII logging disabled. Default Logger does not capture any PII or OII +Logging.piiLoggingEnabled = false + +//PII or OII logging enabled +Logging.piiLoggingEnabled = true + +``` - Logging = { - level: 3, - log: function (message) { - console.log(message); - } - }; ### Security Tokens are accessible from JavaScript since ADAL.JS is using HTML5 storage. Default storage option is sessionStorage, which keeps the tokens per session. You should prompt users to login again for important operations on your app. From f20a0ddde2faef87f87aae8e6aafe4de2c6b7a50 Mon Sep 17 00:00:00 2001 From: Navya Canumalla Date: Tue, 3 Apr 2018 17:23:05 -0700 Subject: [PATCH 02/36] Update repo url in contributing guide --- contributing.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contributing.md b/contributing.md index dba26546..4b2d79fa 100644 --- a/contributing.md +++ b/contributing.md @@ -19,7 +19,7 @@ Example for JS: ``` $ git clone git@github.com:username/azure-activedirectory-library-for-js.git $ cd azure-activedirectory-library-for-js -$ git remote add upstream git@github.com:MSOpenTech/azure-activedirectory-library-for-js.git +$ git remote add upstream git@github.com:AzureAD/azure-activedirectory-library-for-js.git ``` Now decide if you want your feature or bug fix to go into the dev branch @@ -122,5 +122,5 @@ feature branch. Post a comment in the pull request afterwards; GitHub does not send out notifications when you add commits. -[on GitHub]: https://github.com/MSOpenTech/azure-activedirectory-library-for-js -[issue tracker]: https://github.com/MSOpenTech/azure-activedirectory-library-for-js/issues +[on GitHub]: https://github.com/AzureAD/azure-activedirectory-library-for-js +[issue tracker]: https://github.com/AzureAD/azure-activedirectory-library-for-js/issues From 5e3f95ff8f9c34b033900232cd3358444f8dbe08 Mon Sep 17 00:00:00 2001 From: Rohit Narula Date: Thu, 19 Apr 2018 16:00:54 -0700 Subject: [PATCH 03/36] fixed issue with interceptor --- lib/adal-angular.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/adal-angular.js b/lib/adal-angular.js index 22a17170..0f69b338 100644 --- a/lib/adal-angular.js +++ b/lib/adal-angular.js @@ -491,7 +491,7 @@ $rootScope.$on('adal:loginSuccess', function (event, token) { if (token) { authService.info('Login completed, sending request for ' + config.url); - config.headers.Authorization = 'Bearer ' + tokenStored; + config.headers.Authorization = 'Bearer ' + token; delayedRequest.resolve(config); } }); From 49ecdcc655312a111d470858cb424c3c609de4d7 Mon Sep 17 00:00:00 2001 From: Navya Canumalla Date: Fri, 4 May 2018 16:01:16 -0700 Subject: [PATCH 04/36] Link to Wiki from Readme Moving usage and details to wiki --- README.md | 343 +----------------------------------------------------- 1 file changed, 6 insertions(+), 337 deletions(-) diff --git a/README.md b/README.md index 9a718b06..0da7674f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Active Directory Authentication Library (ADAL) for JavaScript ==================================== -|[Getting Started](https://github.com/Azure-Samples/active-directory-javascript-singlepageapp-dotnet-webapi)| [Docs](https://aka.ms/aaddev)| [Samples](https://github.com/azure-samples?query=active-directory)| [Support](README.md#community-help-and-support) +|[Getting Started](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki)| [Docs](https://aka.ms/aaddev)| [Samples](https://github.com/azure-samples?query=active-directory)| [Support](README.md#community-help-and-support) | --- | --- | --- | --- | Active Directory Authentication Library for JavaScript (ADAL JS) helps you to use Azure AD for handling authentication in your single page applications. @@ -8,349 +8,18 @@ This library works with both plain JS as well as AngularJS applications. [![Build Status](https://travis-ci.org/AzureAD/azure-activedirectory-library-for-js.svg?branch=master)](https://travis-ci.org/AzureAD/azure-activedirectory-library-for-js)[![npm](https://img.shields.io/npm/v/adal-angular.svg)](https://www.npmjs.com/package/adal-angular)[![npm](https://img.shields.io/npm/dm/adal-angular.svg)](https://www.npmjs.com/package/adal-angular) -## Installation +You can learn in detail about ADAL JS functionality and usage documented in the [Wiki](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki). -You have multiple ways of getting ADAL JS: - -Via NPM: - - npm install adal-angular - -*Note:* Currently there is one NPM package providing both the plain JS library (adal.js) and the AngularJS wrapper (adal-angular.js). - -Via CDN: - - - - - -CDN will be updated to latest version 1.0.17. - -Via Bower: - - $ bower install adal-angular - -The adal.js source is [here](https://github.com/AzureAD/azure-activedirectory-library-for-js/tree/master/lib/adal.js). -The adal-angular.js source is [here](https://github.com/AzureAD/azure-activedirectory-library-for-js/tree/master/lib/adal-angular.js). - -## Usage - -**In JavaScript** - -You can use ADAL JS as follows in a plain JavaScript application without any frameworks. - -1- Include a reference to adal.js in your main app page before your application scripts. - -```html - - -``` - -2- Initialize ADAL with the AAD app coordinates at app config time. The minimum required config to initialize ADAL is: -```js -window.config = { - clientId: 'g075edef-0efa-453b-997b-de1337c29185' -}; -var authContext = new AuthenticationContext(config); -``` - -3- You can trigger the login and logout using the authContext -```js -$signInButton.click(function () { - authContext.login(); -}); - -$signOutButton.click(function () { - authContext.logOut(); -}); -``` - -Refer this [sample](https://github.com/Azure-Samples/active-directory-javascript-singlepageapp-dotnet-webapi) for a full implementation example. - -**In AngularJS** - -ADAL also provides an AngularJS wrapper as adal-angular.js. Below you can find a quick reference for the most common operations you need to perform in AngularJS applications to use ADAL JS. - -1- Include references to angular.js libraries, adal.js, adal-angular.js in your main app page. The ADAL should be included after Angular, but before your application scripts as shown below. -```html - - - - - -``` - -2- Include a reference to the ADAL module in your app module. -```js -var app = angular.module('demoApp', ['ngRoute', 'AdalAngular']); -``` - -3- ***When HTML5 mode is configured***, ensure the $locationProvider hashPrefix is set - -```js -// using '!' as the hashPrefix but can be a character of your choosing -app.config(['$locationProvider', function($locationProvider) { - $locationProvider.html5Mode(true).hashPrefix('!'); -}]); -``` - -Without the hashPrefix set, the AAD login will loop indefinitely as the callback URL from AAD (in the form of, {yourBaseUrl}/#{AADTokenAndState}) will be rewritten to remove the '#' causing the token parsing to fail and login sequence to occur again. - -4- Initialize ADAL with the AAD app coordinates at app config time. The minimum required config to initialize ADAL is: -```js -adalAuthenticationServiceProvider.init({ - // clientId is the identifier assigned to your app by Azure Active Directory. - clientId: "e9a5a8b6-8af7-4719-9821-0deef255f68e" - }, - $httpProvider // pass http provider to inject request interceptor to attach tokens -); -``` - -5- Define which routes you want to secure via ADAL - by adding `requireADLogin: true` to their definition -```js -$routeProvider. - when("/todoList", { - controller: "todoListController", - templateUrl: "/App/Views/todoList.html", - requireADLogin: true - }); - -``` -Any service invocation code you might have will remain unchanged. ADAL's interceptor will automatically add tokens for every outgoing call. - -Anonymous endpoints, introduced in version 1.0.10, is an array of values that will be ignored by the ADAL route/state change handlers. ADAL will not attach a token to outgoing requests that have these keywords or URI. Routes that *do not* specify the ```requireADLogin=true``` property are added to the ```anonymousEndpoints``` array automatically. - -***Optional*** - -If you so choose, in addition (or substitution) to route level protection you can add explicit login/logout UX elements. Furthermore, you can access properties of the currently signed in user directly form JavaScript (via userInfo and userInfo.profile). -The userInfo.profile property provides access to the claims in the ID token received from AAD. The claims can be used by the application for validation, to identify the subject's directory tenant, and so on. The complete list of claims with a brief description of each value is here, [Claims in Azure AD Security Tokens](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-authentication-scenarios): -```html - - - - Angular Adal Sample - - - Home - ToDo List - - - -
- Welcome {{userInfo.userName}} - - - -
- {{userInfo.loginError}} -
-
- {{testMessage}} -
-
-
- Your view will appear here. -
- - - - - - - - - - - - -``` -6- You have full control on how to trigger sign in, sign out and how to deal with errors: - -```js -'use strict'; -app.controller('homeController', ['$scope', '$location', 'adalAuthenticationService', function ($scope, $location, adalAuthenticationService) { - // this is referencing adal module to do login - - //userInfo is defined at the $rootscope with adalAngular module - $scope.testMessage = ""; - $scope.init = function () { - $scope.testMessage = ""; - }; - - $scope.logout = function () { - adalAuthenticationService.logOut(); - }; - - $scope.login = function () { - adalAuthenticationService.login(); - }; - - // optional - $scope.$on("adal:loginSuccess", function () { - $scope.testMessage = "loginSuccess"; - }); - - // optional - $scope.$on("adal:loginFailure", function () { - $scope.testMessage = "loginFailure"; - $location.path("/login"); - }); - - // optional - $scope.$on("adal:notAuthorized", function (event, rejection, forResource) { - $scope.testMessage = "It is not Authorized for resource:" + forResource; - }); - -}]); -``` - -### Multi-Tenant - -By default, you have multi-tenant support. ADAL will set tenant to 'common', if it is not specified in the config. This allows any Microsoft account to authenticate to your application. If you are not interested in multi-tenant behavior, you will need to set the ```tenant``` property as shown below. - -```js -window.config = { - tenant: "52d4b072-9470-49fb-8721-bc3a1c9912a1", // Optional by default, it sends common - clientId: 'g075edef-0efa-453b-997b-de1337c29185' -}; -``` -If you allow multi-tenant authentication, and you do not wish to allow all Microsoft account users to use your application, you must provide your own method of filtering the token issuers to only those tenants who are allowed to login. - -### Cache Location -Default storage location is sessionStorage. You can specify localStorage in the config as well. - -```js -window.config = { - clientId: 'g075edef-0efa-453b-997b-de1337c29185', - cacheLocation: 'localStorage' // optional cache location. Default is sessionStorage -}; -``` - -### Logging - -Log levels are mapped as: - - 0: Error - 1: Warning - 2: Info - 3: Verbose - -You can add the code below to app.js to turn on logging. Implement the `log` method depending on how you want to redirect logs. -```javascript -Logging = { - level: 3, - log: function (message) { - console.log(message); - }, - piiLoggingEnabled: false -}; -``` -#### Personal Identifiable Information (PII) & Organizational Identifiable Information (OII) - -By default, ADAL logging does not capture or log any PII or OII. The library allows app developers to turn this on by configuring the `piiLoggingEnabled` flag on the log context. By turning on PII or OII, the app takes responsibility for safely handling highly-sensitive data and complying with any regulatory requirements. - -```javascript -//PII or OII logging disabled. Default Logger does not capture any PII or OII -Logging.piiLoggingEnabled = false - -//PII or OII logging enabled -Logging.piiLoggingEnabled = true - -``` - - -### Security -Tokens are accessible from JavaScript since ADAL.JS is using HTML5 storage. Default storage option is sessionStorage, which keeps the tokens per session. You should prompt users to login again for important operations on your app. -You should protect your site for XSS. Please check the article here: [https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) - - -### CORS API usage and IE -ADAL will get access token using Iframe for the given CORS API endpoints in the config. The Iframe needs to access cookies for the same domain that you did the initial sign in. Since IE does not allow to access cookies in an IFrame for localhost, your URL needs to be a fully qualified domain i.e http://yoursite.azurewebsites.com. Chrome does not have this restriction. - -To make CORS API call, you need to specify endpoints in the config for your CORS API as shown here. - -```js -// endpoint to resource mapping(optional) -var endpoints = { - "https://yourhost/api": "b6a68585-5287-45b2-ba82-383ba1f60932", -}; -adalAuthenticationServiceProvider.init( - { - tenant: "52d4b072-9470-49fb-8721-bc3a1c9912a1", // Optional by default, it sends common - clientId: "e9a5a8b6-8af7-4719-9821-0deef255f68e", // Required - endpoints: endpoints // If you need to send CORS API requests. - }, - $httpProvider // pass http provider to inject request interceptor to attach tokens -); -``` - -Your service will be as shown below to make the call from JS. In your API project, you need to enable CORS API requests to receive pre-flight requests. You can check this [sample](https://github.com/AzureADSamples/SinglePageApp-WebAPI-AngularJS-DotNet) for CORS API. - -```js -'use strict'; -app.factory('contactService', ['$http', function ($http) { - var serviceFactory = {}; - - var _getItems = function () { - $http.defaults.useXDomain = true; - delete $http.defaults.headers.common['X-Requested-With']; - return $http.get('http://adaljscors.azurewebsites.net/api/contacts'); - }; - - serviceFactory.getItems = _getItems; - - return serviceFactory; -}]); -``` - -You can read extended blogs about CORS API below. - -Andrew's blog related to CORS and Office365 usage - -http://www.andrewconnell.com/blog/adal-js-cors-with-o365-apis-files-sharepoint - -Vittorio's blog - -http://www.cloudidentity.com/blog/2015/02/19/introducing-adal-js-v1/ -http://www.cloudidentity.com/blog/2014/10/28/adal-javascript-and-angularjs-deep-dive/ - -### Trusted Site settings in IE -If you put your site in the trusted site list, cookies are not accessible for iFrame requests. You need to remove protected mode for Internet zone or add the authority URL for the login to the trusted sites as well. - -### Known issues on Edge -Certain issues have been reported when using ADAL.js with the Microsoft Edge version 40.15063.0.0. Please take a look at [this page](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/Known-issues-on-Edge) for details and workarounds before filing a new issue experienced with Edge. - -## Build and run tests - -**Run tests** - - npm install - bower install - npm test - - // angular tests - karma start - -To use Karma as test runner, you need to install the karma command line. - - npm install -g karma - npm install -g karma-cli - -**Reference doc generation** - -Install grunt and run the command +## Versions - grunt doc +Current version - **1.0.17** +Minimum recommended version - 1.0.11 +You can find the changes for each version in the [change log](https://github.com/AzureAD/azure-activedirectory-library-for-js/blob/master/changelog.txt). ## Contribution We encourage and welcome contributions to the library. Please read the [contributing guide](./contributing.md) before starting. -## Versions -This is a GA released version. Current version - **1.0.17** -Minimum recommended version - 1.0.11 -You can find the changes for each version in the [change log](https://github.com/AzureAD/azure-activedirectory-library-for-js/blob/master/changelog.txt). - ## Samples and Documentation [We provide a full suite of sample applications and documentation on GitHub](https://github.com/azure-samples?query=active-directory) to help you get started with learning the Azure Identity system. This includes tutorials for native clients such as Windows, Windows Phone, iOS, OSX, Android, and Linux; and a detailed guide to registering your app with Azure Active Directory. We also provide full walkthroughs for authentication flows such as OAuth2, OpenID Connect, Graph API, and other awesome features. From 1188c1617ebbc82228ef14b838ef2b09d601d184 Mon Sep 17 00:00:00 2001 From: Rohit Narula Date: Thu, 31 May 2018 13:18:40 -0700 Subject: [PATCH 05/36] fixed issue with responseType id_token token --- lib/adal.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/adal.js b/lib/adal.js index 1f073ebd..90185008 100644 --- a/lib/adal.js +++ b/lib/adal.js @@ -1213,17 +1213,16 @@ var AuthenticationContext = (function () { this._user = null; } else { this._saveItem(this.CONSTANTS.STORAGE.IDTOKEN, requestInfo.parameters[this.CONSTANTS.ID_TOKEN]); - // Save idtoken as access token for app itself - resource = this.config.loginResource ? this.config.loginResource : this.config.clientId; + var idTokenResource = this.config.loginResource ? this.config.loginResource : this.config.clientId; - if (!this._hasResource(resource)) { + if (!this._hasResource(idTokenResource)) { keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS) || ''; - this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, keys + resource + this.CONSTANTS.RESOURCE_DELIMETER); + this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, keys + idTokenResource + this.CONSTANTS.RESOURCE_DELIMETER); } - this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource, requestInfo.parameters[this.CONSTANTS.ID_TOKEN]); - this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, this._user.profile.exp); + this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + idTokenResource, requestInfo.parameters[this.CONSTANTS.ID_TOKEN]); + this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + idTokenResource, this._user.profile.exp); } } else { From 68d3235b743d9181249cbe3f3cc8f8cbe9aac562 Mon Sep 17 00:00:00 2001 From: Navya Canumalla Date: Wed, 6 Jun 2018 18:15:05 -0700 Subject: [PATCH 06/36] Add sample links to Readme --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0da7674f..186b1063 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ Active Directory Authentication Library (ADAL) for JavaScript ==================================== -|[Getting Started](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki)| [Docs](https://aka.ms/aaddev)| [Samples](https://github.com/azure-samples?query=active-directory)| [Support](README.md#community-help-and-support) +|[Getting Started](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki)| [Docs](https://aka.ms/aaddev)| [Samples](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/Code-samples)| [Support](README.md#community-help-and-support) | --- | --- | --- | --- | Active Directory Authentication Library for JavaScript (ADAL JS) helps you to use Azure AD for handling authentication in your single page applications. This library works with both plain JS as well as AngularJS applications. -[![Build Status](https://travis-ci.org/AzureAD/azure-activedirectory-library-for-js.svg?branch=master)](https://travis-ci.org/AzureAD/azure-activedirectory-library-for-js)[![npm](https://img.shields.io/npm/v/adal-angular.svg)](https://www.npmjs.com/package/adal-angular)[![npm](https://img.shields.io/npm/dm/adal-angular.svg)](https://www.npmjs.com/package/adal-angular) +[![Build Status](https://travis-ci.org/AzureAD/azure-activedirectory-library-for-js.svg?branch=dev)](https://travis-ci.org/AzureAD/azure-activedirectory-library-for-js)[![npm](https://img.shields.io/npm/v/adal-angular.svg)](https://www.npmjs.com/package/adal-angular)[![npm](https://img.shields.io/npm/dm/adal-angular.svg)](https://www.npmjs.com/package/adal-angular) -You can learn in detail about ADAL JS functionality and usage documented in the [Wiki](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki). +## Usage + +You can learn in detail about ADAL JS installation and usage documented in the [ADAL Basics Wiki](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/ADAL-basics). ## Versions @@ -22,7 +24,9 @@ We encourage and welcome contributions to the library. Please read the [contribu ## Samples and Documentation -[We provide a full suite of sample applications and documentation on GitHub](https://github.com/azure-samples?query=active-directory) to help you get started with learning the Azure Identity system. This includes tutorials for native clients such as Windows, Windows Phone, iOS, OSX, Android, and Linux; and a detailed guide to registering your app with Azure Active Directory. We also provide full walkthroughs for authentication flows such as OAuth2, OpenID Connect, Graph API, and other awesome features. +Please refer these [code samples using ADAL.js](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/Code-samples) based on your application scenario. + +You can also find a [full suite of sample applications](https://github.com/azure-samples?query=active-directory) and [documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-developers-guide) to help you get started with learning the Azure Identity system. This includes tutorials for multiple platforms; and a detailed guide to registering your app with Azure Active Directory. We also provide full walkthroughs for authentication flows such as OAuth2, OpenID Connect, Graph API, and other awesome features. ## Community Help and Support From f4c81df809a48d9f2ad354c4bf8e4755b3263788 Mon Sep 17 00:00:00 2001 From: Maciej Kumorek Date: Tue, 17 Jul 2018 18:26:26 -0700 Subject: [PATCH 07/36] Cache the values of _supportsLocalStorage and _supportsSessionStorage --- lib/adal.js | 59 ++++++++++++++++++++++++------------- tests/unit/spec/AdalSpec.js | 16 ++++++++++ 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/lib/adal.js b/lib/adal.js index 90185008..5f61ff0d 100644 --- a/lib/adal.js +++ b/lib/adal.js @@ -135,6 +135,10 @@ var AuthenticationContext = (function () { this._openedWindows = []; this._requestType = this.REQUEST_TYPE.LOGIN; window._adalInstance = this; + this._storageSupport = { + localStorage: null, + sessionStorage: null + }; // validate before constructor assignments if (config.displayCall && typeof config.displayCall !== 'function') { @@ -924,7 +928,7 @@ var AuthenticationContext = (function () { * @ignore */ AuthenticationContext.prototype._addHintParameters = function (urlNavigate) { - //If you don’t use prompt=none, then if the session does not exist, there will be a failure. + //If you don�t use prompt=none, then if the session does not exist, there will be a failure. //If sid is sent alongside domain or login hints, there will be a failure since request is ambiguous. //If sid is sent with a prompt value other than none or attempt_none, there will be a failure since the request is ambiguous. @@ -1759,20 +1763,44 @@ var AuthenticationContext = (function () { }; /** - * Returns true if browser supports localStorage, false otherwise. + * Returns true if the browser supports given storage type * @ignore */ - AuthenticationContext.prototype._supportsLocalStorage = function () { + AuthenticationContext.prototype._supportsStorage = function(storageType) { + if (!(storageType in this._storageSupport)) { + return false; + } + + if (this._storageSupport[storageType] !== null) { + return this._storageSupport[storageType]; + } + try { - if (!window.localStorage) return false; // Test availability - window.localStorage.setItem('storageTest', 'A'); // Try write - if (window.localStorage.getItem('storageTest') != 'A') return false; // Test read/write - window.localStorage.removeItem('storageTest'); // Try delete - if (window.localStorage.getItem('storageTest')) return false; // Test delete - return true; // Success + if (!(storageType in window) || window[storageType] === null) { + throw new Error(); + } + var testKey = '__storageTest__'; + window[storageType].setItem(testKey, 'A'); + if (window[storageType].getItem(testKey) !== 'A') { + throw new Error(); + } + window[storageType].removeItem(testKey); + if (window[storageType].getItem(testKey)) { + throw new Error(); + } + this._storageSupport[storageType] = true; } catch (e) { - return false; + this._storageSupport[storageType] = false; } + return this._storageSupport[storageType]; + } + + /** + * Returns true if browser supports localStorage, false otherwise. + * @ignore + */ + AuthenticationContext.prototype._supportsLocalStorage = function () { + return this._supportsStorage('localStorage'); }; /** @@ -1780,16 +1808,7 @@ var AuthenticationContext = (function () { * @ignore */ AuthenticationContext.prototype._supportsSessionStorage = function () { - try { - if (!window.sessionStorage) return false; // Test availability - window.sessionStorage.setItem('storageTest', 'A'); // Try write - if (window.sessionStorage.getItem('storageTest') != 'A') return false; // Test read/write - window.sessionStorage.removeItem('storageTest'); // Try delete - if (window.sessionStorage.getItem('storageTest')) return false; // Test delete - return true; // Success - } catch (e) { - return false; - } + return this._supportsStorage('sessionStorage'); }; /** diff --git a/tests/unit/spec/AdalSpec.js b/tests/unit/spec/AdalSpec.js index 39dbc6b0..a7dd11c3 100644 --- a/tests/unit/spec/AdalSpec.js +++ b/tests/unit/spec/AdalSpec.js @@ -1098,4 +1098,20 @@ describe('Adal', function () { expect(Logging.level).toEqual(2); Logging.piiLoggingEnabled = false; }) + + it('checks if localStorage is available', function () { + expect(adal._supportsLocalStorage()).toBe(true); + }) + + it('reports localStorage unavailable if window.localStorage is null', function () { + window.localStorage = null; + expect(adal._supportsLocalStorage()).toBe(false); + }) + + it('reports localStorage unavailable if window.localStorage fails to save', function () { + window.localStorage.setItem = function(key, value) { + return; + } + expect(adal._supportsLocalStorage()).toBe(false); + }) }); From d426f80224ccc10e09cfd162b0c7ee0b38a99143 Mon Sep 17 00:00:00 2001 From: aashiman Date: Fri, 3 Aug 2018 08:57:12 -0700 Subject: [PATCH 08/36] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d1dc6fc7..6708ee2a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Active Directory Authentication Library (ADAL) for JavaScript ==================================== -|[Getting Started](https://github.com/Azure-Samples/active-directory-javascript-singlepageapp-dotnet-webapi)| [Docs](https://aka.ms/aaddev)| [Samples](https://github.com/azure-samples?query=active-directory)| [Support](README.md#community-help-and-support) -| --- | --- | --- | --- | +|[Getting Started](https://github.com/Azure-Samples/active-directory-javascript-singlepageapp-dotnet-webapi)| [Docs](https://aka.ms/aaddev)| [Library Reference](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AzureAD/azure-activedirectory-library-for-js/blob/dev/doc/AuthenticationContext.html) | [Samples](https://github.com/azure-samples?query=active-directory)| [Support](README.md#community-help-and-support) +| --- | --- | --- | Active Directory Authentication Library for JavaScript (ADAL JS) helps you to use Azure AD for handling authentication in your single page applications. This library works with both plain JS as well as AngularJS applications. From 88c6cbf735dd336b87e11f7442c61b68125ed98c Mon Sep 17 00:00:00 2001 From: aashiman Date: Fri, 3 Aug 2018 09:00:19 -0700 Subject: [PATCH 09/36] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6708ee2a..776dc4f0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Active Directory Authentication Library (ADAL) for JavaScript ==================================== -|[Getting Started](https://github.com/Azure-Samples/active-directory-javascript-singlepageapp-dotnet-webapi)| [Docs](https://aka.ms/aaddev)| [Library Reference](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AzureAD/azure-activedirectory-library-for-js/blob/dev/doc/AuthenticationContext.html) | [Samples](https://github.com/azure-samples?query=active-directory)| [Support](README.md#community-help-and-support) -| --- | --- | --- | +| [Getting Started](https://github.com/Azure-Samples/active-directory-javascript-singlepageapp-dotnet-webapi)| [Docs](https://aka.ms/aaddev)| [Library Reference](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AzureAD/azure-activedirectory-library-for-js/blob/dev/doc/AuthenticationContext.html) | [Samples](https://github.com/azure-samples?query=active-directory)| [Support](README.md#community-help-and-support) +| --- | --- | --- |--- | --- | Active Directory Authentication Library for JavaScript (ADAL JS) helps you to use Azure AD for handling authentication in your single page applications. This library works with both plain JS as well as AngularJS applications. From d9bf200b1b8f935897ecc31159adc05f36be7af6 Mon Sep 17 00:00:00 2001 From: Rohit Narula Date: Wed, 3 Oct 2018 11:22:31 -0700 Subject: [PATCH 10/36] fixed callback issue with acquireTokenRedirect api --- lib/adal.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/adal.js b/lib/adal.js index 90185008..1b54149e 100644 --- a/lib/adal.js +++ b/lib/adal.js @@ -747,23 +747,25 @@ var AuthenticationContext = (function () { * @param {string} extraQueryParameters extraQueryParameters to add to the authentication request */ AuthenticationContext.prototype.acquireTokenRedirect = function (resource, extraQueryParameters, claims) { + var callback = this.callback; if (this._isEmpty(resource)) { this.warn('resource is required'); - callback('resource is required', null, 'resource is required'); + if (callback) + callback('resource is required', null, 'resource is required'); return; } - var callback = this.callback; - if (!this._user) { this.warn('User login is required'); - callback('User login is required', null, 'login required'); + if (callback) + callback('User login is required', null, 'login required'); return; } if (this._acquireTokenInProgress) { this.warn("Acquire token interactive is already in progress") - callback("Acquire token interactive is already in progress", null, "Acquire token interactive is already in progress"); + if (callback) + callback("Acquire token interactive is already in progress", null, "Acquire token interactive is already in progress"); return; } From d018e74c308a9cda75161d4b68e72ab05d92f761 Mon Sep 17 00:00:00 2001 From: Rohit Narula Date: Wed, 3 Oct 2018 11:49:01 -0700 Subject: [PATCH 11/36] removed dependencies for node versions 0.10 and 0.11 --- .travis.yml | 6 +----- lib/adal.js | 16 +++++++--------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index fb027fb2..0fe294a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,3 @@ language: node_js node_js: - - "0.11" - - "0.10" - - "4.7.3" - - "5.12.0" - - "6.1.0" + - "7" diff --git a/lib/adal.js b/lib/adal.js index 1b54149e..0218e1a5 100644 --- a/lib/adal.js +++ b/lib/adal.js @@ -747,25 +747,23 @@ var AuthenticationContext = (function () { * @param {string} extraQueryParameters extraQueryParameters to add to the authentication request */ AuthenticationContext.prototype.acquireTokenRedirect = function (resource, extraQueryParameters, claims) { - var callback = this.callback; if (this._isEmpty(resource)) { this.warn('resource is required'); - if (callback) - callback('resource is required', null, 'resource is required'); + callback('resource is required', null, 'resource is required'); return; } + var callback = this.callback; + if (!this._user) { this.warn('User login is required'); - if (callback) - callback('User login is required', null, 'login required'); + callback('User login is required', null, 'login required'); return; } if (this._acquireTokenInProgress) { this.warn("Acquire token interactive is already in progress") - if (callback) - callback("Acquire token interactive is already in progress", null, "Acquire token interactive is already in progress"); + callback("Acquire token interactive is already in progress", null, "Acquire token interactive is already in progress"); return; } @@ -926,7 +924,7 @@ var AuthenticationContext = (function () { * @ignore */ AuthenticationContext.prototype._addHintParameters = function (urlNavigate) { - //If you don’t use prompt=none, then if the session does not exist, there will be a failure. + //If you don?t use prompt=none, then if the session does not exist, there will be a failure. //If sid is sent alongside domain or login hints, there will be a failure since request is ambiguous. //If sid is sent with a prompt value other than none or attempt_none, there will be a failure since the request is ambiguous. @@ -1937,4 +1935,4 @@ var AuthenticationContext = (function () { return AuthenticationContext; -}()); +}()); \ No newline at end of file From a2a4a64ad80cdb9c17697ec46532ce30325445ff Mon Sep 17 00:00:00 2001 From: Rohit Narula Date: Wed, 3 Oct 2018 12:10:51 -0700 Subject: [PATCH 12/36] fixed minor iframe border issue --- lib/adal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/adal.js b/lib/adal.js index 90185008..ce1e4d36 100644 --- a/lib/adal.js +++ b/lib/adal.js @@ -1684,7 +1684,7 @@ var AuthenticationContext = (function () { ifr.setAttribute('aria-hidden', 'true'); ifr.style.visibility = 'hidden'; ifr.style.position = 'absolute'; - ifr.style.width = ifr.style.height = ifr.borderWidth = '0px'; + ifr.style.width = ifr.style.height = ifr.style.borderWidth = '0px'; adalFrame = document.getElementsByTagName('body')[0].appendChild(ifr); } From 37aef7026ef59e0dee0f0e0d8eb62c768c450fd7 Mon Sep 17 00:00:00 2001 From: rohitnarula7176 Date: Wed, 3 Oct 2018 15:12:38 -0700 Subject: [PATCH 13/36] updated code as per PR comments --- .travis.yml | 5 ++++- lib/adal.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0fe294a6..b3153dfd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,6 @@ language: node_js node_js: - - "7" + - "node" +cache: + directories: + - "node_modules" \ No newline at end of file diff --git a/lib/adal.js b/lib/adal.js index 0218e1a5..3ca8e356 100644 --- a/lib/adal.js +++ b/lib/adal.js @@ -924,7 +924,7 @@ var AuthenticationContext = (function () { * @ignore */ AuthenticationContext.prototype._addHintParameters = function (urlNavigate) { - //If you don?t use prompt=none, then if the session does not exist, there will be a failure. + //If you don't use prompt=none, then if the session does not exist, there will be a failure. //If sid is sent alongside domain or login hints, there will be a failure since request is ambiguous. //If sid is sent with a prompt value other than none or attempt_none, there will be a failure since the request is ambiguous. From 8184d79dbaec8dbd823fa77fc161298044afd995 Mon Sep 17 00:00:00 2001 From: rohitnarula7176 Date: Wed, 3 Oct 2018 21:42:39 -0700 Subject: [PATCH 14/36] set user to null in clear cache --- lib/adal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/adal.js b/lib/adal.js index 3ca8e356..b050e077 100644 --- a/lib/adal.js +++ b/lib/adal.js @@ -809,6 +809,7 @@ var AuthenticationContext = (function () { * Clears cache items. */ AuthenticationContext.prototype.clearCache = function () { + this._user = null; this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST, ''); this._saveItem(this.CONSTANTS.STORAGE.ANGULAR_LOGIN_REQUEST, ''); this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE, ''); @@ -855,7 +856,6 @@ var AuthenticationContext = (function () { */ AuthenticationContext.prototype.logOut = function () { this.clearCache(); - this._user = null; var urlNavigate; if (this.config.logOutUri) { From 9fbcf4ae5d44ed84e43f036dc4023ff006f48c52 Mon Sep 17 00:00:00 2001 From: rohitnarula7176 Date: Wed, 3 Oct 2018 22:40:31 -0700 Subject: [PATCH 15/36] fixed circular reference error in JSON.stringify --- lib/adal-angular.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/adal-angular.js b/lib/adal-angular.js index 0f69b338..09ed29e5 100644 --- a/lib/adal-angular.js +++ b/lib/adal-angular.js @@ -315,7 +315,7 @@ }; var stateChangeErrorHandler = function (event, toState, toParams, fromState, fromParams, error) { - _adal.verbose("State change error occured. Error: " + typeof (error) === 'string' ? error : JSON.stringify(error)); + _adal.verbose("State change error occured. Error: " + typeof (error) === 'string' ? error : JSON.stringify(error, jsonCircularReferenceReplacer())); // adal interceptor sets the error on config.data property. If it is set, it means state change is rejected by adal, // in which case set the defaultPrevented to true to avoid url update as that sometimesleads to infinte loop. if (error && error.data) { @@ -325,6 +325,19 @@ } }; + var jsonCircularReferenceReplacer = function () { + var cache = []; + return function (key, value) { + if (typeof value === "object" && value !== null) { + if (cache.indexOf(value) !== -1) { + return; + } + cache.push(value); + } + return value; + }; + } + if ($injector.has('$transitions')) { var $transitions = $injector.get('$transitions'); @@ -527,7 +540,7 @@ } }, responseError: function (rejection) { - authService.info('Getting error in the response: ' + JSON.stringify(rejection)); + authService.info('Getting error in the response: ' + JSON.stringify(rejection, jsonCircularReferenceReplacer())); if (rejection) { if (rejection.status === 401) { var resource = authService.getResourceForEndpoint(rejection.config.url); From 2e942f94eb6bb21fb1f0f8e124b6489ee61cab4b Mon Sep 17 00:00:00 2001 From: wenYorker Date: Wed, 24 Oct 2018 10:11:35 -0700 Subject: [PATCH 16/36] creating issue_template --- issue_template.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 issue_template.md diff --git a/issue_template.md b/issue_template.md new file mode 100644 index 00000000..93825ce4 --- /dev/null +++ b/issue_template.md @@ -0,0 +1,44 @@ + + +## I'm submitting a... + +

+[ ] Regression (a behavior that used to work and stopped working in a new release)
+[ ] Bug report  
+[ ] Performance issue
+[ ] Feature request
+[ ] Documentation issue or request
+[ ] Other... Please describe:
+
+ +## Browser: +- [ ] Chrome version XX +- [ ] Firefox version XX +- [ ] IE version XX +- [ ] Edge version XX +- [ ] Safari version XX + +## Library Name +- [ ] adal.js XX +- [ ] adal-angular XX + +## Library version +Library version: X.Y.Z + + + +## Current behavior + + + +## Expected behavior + + + +## Minimal reproduction of the problem with instructions + + + + From b4387f77bbf1b7adfa721f6e3df579ca9015376c Mon Sep 17 00:00:00 2001 From: Navya Canumalla Date: Wed, 14 Nov 2018 09:27:05 -0800 Subject: [PATCH 17/36] Add ADAL.js usage pattern to readme --- README.md | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 186b1063..6d3fd872 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,113 @@ This library works with both plain JS as well as AngularJS applications. [![Build Status](https://travis-ci.org/AzureAD/azure-activedirectory-library-for-js.svg?branch=dev)](https://travis-ci.org/AzureAD/azure-activedirectory-library-for-js)[![npm](https://img.shields.io/npm/v/adal-angular.svg)](https://www.npmjs.com/package/adal-angular)[![npm](https://img.shields.io/npm/dm/adal-angular.svg)](https://www.npmjs.com/package/adal-angular) -## Usage -You can learn in detail about ADAL JS installation and usage documented in the [ADAL Basics Wiki](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/ADAL-basics). +## Installation + +You have multiple ways of getting ADAL JS: + +Via NPM (https://www.npmjs.com/package/adal-angular): + + npm install adal-angular + +*Note:* Currently there is one NPM package providing both the plain JS library (adal.js) and the AngularJS wrapper (adal-angular.js). + +Via CDN: + + + + + +Via Bower: + + $ bower install adal-angular + +## Usage + +#### Prerequisite + +Before using ADAL JS, follow the instructions to [register your application](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) on the Azure portal. Also, make sure to enable the [OAuth 2.0 implicit flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-implicit-grant-flow) by setting the property `oauth2AllowImplicitFlow` to true by editing your application manifest on the portal. Implicit flow is used by ADAL JS to get tokens. + +#### 1. Instantiate the AuthenticationContext + +Instantiate the global variable AuthenticationContext with a minimal required config of clientID. You can read about other configurable options [here](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/Config-authentication-context#configurable-options). + +```JavaScript +window.config = { + clientId: '[Enter your client_id here, e.g. g075edef-0efa-453b-997b-de1337c29185]', + popUp: true +}; + +var authContext = new AuthenticationContext(config); +``` + +#### 2. Login the user + +Your app must login the user to establish user context. The login operates in popup mode if you set the option `popUp: true` as shown in the config above. + +```JavaScript +var user = authenticationContext.getCachedUser(); +if (user) { + // Use the logged in user information + onLogin(null, user); +} +else { + // Initiate login + authenticationContext.login(); +} +``` + +#### 3. Get an access token + +Next, you can get access tokens for the APIs your app needs to call using the acquireToken method which attempts to acquire token silently. The acquireToken method takes a callback function as shown below. + +If the silent token acquisition fails for some reasons such as an expired session or password change, you will need to invoke one of the interactive methods to acquire tokens. + + ```JavaScript + authenticationContext.acquireToken(webApiConfig.resourceId, function (errorDesc, token, error) { + if (error) { //acquire token failure + if (config.popUp) { + // If using popup flows + authenticationContext.acquireTokenPopup(webApiConfig.resourceId, null, null, onAccessToken); + } + else { + authenticationContext.acquireTokenRedirect(webApiConfig.resourceId, null, null); + } + } + else { + //acquired token successfully + } + }); +} +``` + +**Note:** In ADAL JS, you will have to explicitly call the handleWindowCallback method on page load to handle the response from the server in case of redirect flows - login without popup and acquireTokenRedirect. + +```JavaScript +if (authenticationContext.isCallback(window.location.hash)) { + authenticationContext.handleWindowCallback(); +} +``` + +#### 4. Use the token as a bearer in an HTTP request to call the Microsoft Graph or a Web API + +```JavaScript + var headers = new Headers(); + var bearer = "Bearer " + token; + headers.append("Authorization", bearer); + var options = { + method: "GET", + headers: headers + }; + var graphEndpoint = "https://graph.microsoft.com/v1.0/me"; + + fetch(graphEndpoint, options) + .then(function (response) { + //do something with response + } +``` + +You can learn further details about ADAL.js functionality documented in the [ADAL Wiki](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/) and find complete [code samples](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/Code-samples). ## Versions From fe03c4e97b4f52a127c47a45f10d21cf4e786371 Mon Sep 17 00:00:00 2001 From: wenYorker Date: Thu, 15 Nov 2018 10:23:22 -0800 Subject: [PATCH 18/36] update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d3fd872..da639538 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,12 @@ var authContext = new AuthenticationContext(config); #### 2. Login the user -Your app must login the user to establish user context. The login operates in popup mode if you set the option `popUp: true` as shown in the config above. +Your app must login the user to establish user context. The login operates in popup mode if you set the option `popUp: true` instead of a full redirect as shown in the config above.Defaults to `false. ```JavaScript var user = authenticationContext.getCachedUser(); if (user) { - // Use the logged in user information + // Use the logged in user information to call your own api onLogin(null, user); } else { From 0f27ccb81c0579ab50d09c5548f28e172ffcaa21 Mon Sep 17 00:00:00 2001 From: wenYorker Date: Thu, 15 Nov 2018 10:25:31 -0800 Subject: [PATCH 19/36] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index da639538..3732809f 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ If the silent token acquisition fails for some reasons such as an expired sessio } ``` -**Note:** In ADAL JS, you will have to explicitly call the handleWindowCallback method on page load to handle the response from the server in case of redirect flows - login without popup and acquireTokenRedirect. +**Note:** In ADAL JS, you will have to explicitly call the handleWindowCallback method on page load to handle the response from the server in case of redirect flows like login without popup and acquireTokenRedirect. There is no need to call this function for popup flows like loginPopup and acquireTokenPopup. ```JavaScript if (authenticationContext.isCallback(window.location.hash)) { From e8f8524ce55e305091ec68eb373823d1d42a6462 Mon Sep 17 00:00:00 2001 From: wenYorker Date: Thu, 15 Nov 2018 10:40:49 -0800 Subject: [PATCH 20/36] update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3732809f..5b9da6cc 100644 --- a/README.md +++ b/README.md @@ -75,9 +75,10 @@ If the silent token acquisition fails for some reasons such as an expired sessio if (error) { //acquire token failure if (config.popUp) { // If using popup flows - authenticationContext.acquireTokenPopup(webApiConfig.resourceId, null, null, onAccessToken); + authenticationContext.acquireTokenPopup(webApiConfig.resourceId, null, null, function (errorDesc, token, error) {}); } else { + // In this case the callback passed in the Authentication request constructor will be called. authenticationContext.acquireTokenRedirect(webApiConfig.resourceId, null, null); } } From 0d655cd12fcc9362c3b8bedef03647cf95f3e095 Mon Sep 17 00:00:00 2001 From: wenYorker Date: Thu, 15 Nov 2018 11:01:28 -0800 Subject: [PATCH 21/36] update readme --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5b9da6cc..82649647 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,16 @@ Instantiate the global variable AuthenticationContext with a minimal required co ```JavaScript window.config = { clientId: '[Enter your client_id here, e.g. g075edef-0efa-453b-997b-de1337c29185]', - popUp: true + popUp: true, + callback : callbackFunction }; var authContext = new AuthenticationContext(config); + +function callbackFunction(errorDesc, token, error, tokenType) +{ +} + ``` #### 2. Login the user @@ -89,7 +95,7 @@ If the silent token acquisition fails for some reasons such as an expired sessio } ``` -**Note:** In ADAL JS, you will have to explicitly call the handleWindowCallback method on page load to handle the response from the server in case of redirect flows like login without popup and acquireTokenRedirect. There is no need to call this function for popup flows like loginPopup and acquireTokenPopup. +**Note:** In ADAL JS, you will have to explicitly call the handleWindowCallback method on page load to handle the response from the server in case of redirect flows like login without popup and acquireTokenRedirect. There is no need to call this function for popup flows like loginPopup and acquireTokenPopup. This method must be called for processing the response received from AAD. It extracts the hash, processes the token or error, saves it in the cache and calls the registered callback function in your initialization with the result. ```JavaScript if (authenticationContext.isCallback(window.location.hash)) { From 23fafd082ad35f549de3f57e248480fe9c169063 Mon Sep 17 00:00:00 2001 From: wenYorker Date: Thu, 15 Nov 2018 11:18:10 -0800 Subject: [PATCH 22/36] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 82649647..54901990 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ function callbackFunction(errorDesc, token, error, tokenType) #### 2. Login the user -Your app must login the user to establish user context. The login operates in popup mode if you set the option `popUp: true` instead of a full redirect as shown in the config above.Defaults to `false. +Your app must login the user to establish user context. The login operates in popup mode if you set the option `popUp: true` instead of a full redirect as shown in the config above.Defaults to `false. The callback function passed in the Authentication request constructor will be called after the login with success or failure results. ```JavaScript var user = authenticationContext.getCachedUser(); From 13b89a7fbeff563b617e2acb734955a10b8c0fa6 Mon Sep 17 00:00:00 2001 From: nehaagrawal Date: Thu, 29 Nov 2018 11:24:59 -0800 Subject: [PATCH 23/36] Adal release 1.0.18 --- changelog.txt | 9 +++++++++ lib/adal-angular.js | 2 +- lib/adal.js | 4 ++-- package.json | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3bca1cb7..32d44505 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,12 @@ +Version 1.0.18 +========================= +* Fixed circular reference error in JSON.stringify https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/806 +* Set user to null in clear cache https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/807 +* Fixed minor iframe border issue https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/788 https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/682 +* Remove dependency on node version 0.10 and 0.11. https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/799 +* Check if callback function exists before calling it. https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/794 +* Cache the values of _supportsLocalStorage and _supportsSessionStorage. https://github.com/AzureAD/azure-activedirectory-library-for-js/pull/786 + Version 1.0.17 ========================= * Added sid support. When the session id parameter is provided in the id_token, use that instead of the upn diff --git a/lib/adal-angular.js b/lib/adal-angular.js index 09ed29e5..8cd43b68 100644 --- a/lib/adal-angular.js +++ b/lib/adal-angular.js @@ -1,5 +1,5 @@ //---------------------------------------------------------------------- -// AdalJS v1.0.17 +// AdalJS v1.0.18 // @preserve Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // Apache License 2.0 diff --git a/lib/adal.js b/lib/adal.js index 3f9bc70e..5e9a074b 100644 --- a/lib/adal.js +++ b/lib/adal.js @@ -1,5 +1,5 @@ //---------------------------------------------------------------------- -// AdalJS v1.0.17 +// AdalJS v1.0.18 // @preserve Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // Apache License 2.0 @@ -1939,7 +1939,7 @@ var AuthenticationContext = (function () { * @ignore */ AuthenticationContext.prototype._libVersion = function () { - return '1.0.17'; + return '1.0.18'; }; /** diff --git a/package.json b/package.json index d1fca05e..f3f42646 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "type": "git", "url": "https://github.com/AzureAD/azure-activedirectory-library-for-js.git" }, - "version": "1.0.17", + "version": "1.0.18", "description": "Windows Azure Active Directory Client Library for js", "keywords": [ "implicit", From 5f88559446ba5f35dfb1c1149c5c52dce0158b63 Mon Sep 17 00:00:00 2001 From: nehaagrawal Date: Thu, 29 Nov 2018 13:34:24 -0800 Subject: [PATCH 24/36] updated changelog --- changelog.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 32d44505..1f7444f4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,10 +2,12 @@ Version 1.0.18 ========================= * Fixed circular reference error in JSON.stringify https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/806 * Set user to null in clear cache https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/807 -* Fixed minor iframe border issue https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/788 https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/682 +* Fixed minor iframe border issue https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/788 https://github.com/AzureAD/azure-activedirectory-library-for-js/pull/789 * Remove dependency on node version 0.10 and 0.11. https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/799 * Check if callback function exists before calling it. https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/794 * Cache the values of _supportsLocalStorage and _supportsSessionStorage. https://github.com/AzureAD/azure-activedirectory-library-for-js/pull/786 +* Fixed issue with interceptor https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/731 +* Fixed issue with responseType id_token token https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/736 Version 1.0.17 ========================= From 0239b400a2048aa8a8763fa18e068a69219441f6 Mon Sep 17 00:00:00 2001 From: nehaagrawal Date: Thu, 29 Nov 2018 15:42:24 -0800 Subject: [PATCH 25/36] updated dist file --- README.md | 6 +++--- dist/adal-angular.min.js | 4 ++-- dist/adal.min.js | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 54901990..02393d60 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,8 @@ Via NPM (https://www.npmjs.com/package/adal-angular): Via CDN: - - + + Via Bower: @@ -125,7 +125,7 @@ You can learn further details about ADAL.js functionality documented in the [ADA ## Versions -Current version - **1.0.17** +Current version - **1.0.18** Minimum recommended version - 1.0.11 You can find the changes for each version in the [change log](https://github.com/AzureAD/azure-activedirectory-library-for-js/blob/master/changelog.txt). diff --git a/dist/adal-angular.min.js b/dist/adal-angular.min.js index d2cc7f63..76e276ae 100644 --- a/dist/adal-angular.min.js +++ b/dist/adal-angular.min.js @@ -1,2 +1,2 @@ -/*! adal-angular v1.0.17 2018-02-27 */ -!function(){"use strict";if("undefined"!=typeof module&&module.exports&&(module.exports.inject=function(a){return new AuthenticationContext(a)}),angular){var a=angular.module("AdalAngular",[]);a.provider("adalAuthenticationService",function(){var a=null,b={isAuthenticated:!1,userName:"",loginError:"",profile:""},c=function(c){var d=a.getCachedToken(c);b.isAuthenticated=null!==d&&d.length>0;var e=a.getCachedUser()||{userName:""};b.userName=e.userName,b.profile=e.profile,b.loginError=a.getLoginError()};this.init=function(b,d){if(!b)throw new Error("You must set configOptions, when calling init");b.isAngular=!0,d&&d.interceptors&&d.interceptors.push("ProtectedResourceInterceptor"),a=new AuthenticationContext(b),c(a.config.loginResource)},this.$get=["$rootScope","$window","$q","$location","$timeout","$injector",function(d,e,f,g,h,i){function j(a,b){return b.requireADLogin?!1!==a.requireADLogin:!!a.requireADLogin}function k(b){if(a.config&&a.config.anonymousEndpoints)for(var c=0;c-1)return!0;return!1}function l(a){var b=null,c=[];if(a.hasOwnProperty("parent"))for(b=a;b;)c.unshift(b),b=i.get("$state").get(b.parent);else for(var d=a.name.split("."),e=0,f=d[0];e0&&a._openedWindows[a._openedWindows.length-1].opener&&a._openedWindows[a._openedWindows.length-1].opener._adalInstance?(a=a._openedWindows[a._openedWindows.length-1].opener._adalInstance,k=!0):e.parent&&e.parent._adalInstance&&(a=e.parent._adalInstance),a.verbose("Processing the hash: "+f);var l=a.getRequestInfo(f);a.saveTokenFromHash(l);var m=l.parameters.access_token||l.parameters.id_token,n=l.parameters.error,o=l.parameters.error_description,p=null,q=a._callBackMappedToRenewStates[l.stateResponse]||a.callback;if(l.stateMatch){if(l.requestType===a.REQUEST_TYPE.RENEW_TOKEN?(p=a.CONSTANTS.ACCESS_TOKEN,a._renewActive=!1,e.parent!==e||a._callBackMappedToRenewStates[l.stateResponse]||(m?d.$broadcast("adal:acquireTokenSuccess",m):n&&o&&d.$broadcast("adal:acquireTokenFailure",o,n))):l.requestType===a.REQUEST_TYPE.LOGIN&&(p=a.CONSTANTS.ID_TOKEN,c(a.config.loginResource),b.userName?(h(function(){c(a.config.loginResource),d.userInfo=b},1),d.$broadcast("adal:loginSuccess",m)):d.$broadcast("adal:loginFailure",o,n)),q&&"function"==typeof q&&q(o,m,n,p),window.parent!==window)return void(j&&j.preventDefault&&j.preventDefault());if(e.parent===window&&!k)if(a.config.navigateToLoginRequestUrl){var r=a._getItem(a.CONSTANTS.STORAGE.LOGIN_REQUEST);void 0!==r&&r&&0!==r.length&&(a.verbose("Redirecting to start page: "+r),!g.$$html5&&r.indexOf("#")>-1&&g.url(r.substring(r.indexOf("#")+1)),e.location.href=r)}else g.$$html5?g.hash(""):g.path("")}else d.$broadcast("adal:stateMismatch",o,n)}else if(c(a.config.loginResource),!b.isAuthenticated&&b.userName&&!a._renewActive){var s=i.get("adalAuthenticationService");s.acquireToken(a.config.loginResource).then(function(a){a&&(b.isAuthenticated=!0)},function(a){var b=a.split("|");d.$broadcast("adal:loginFailure",b[0],b[1])})}},q=function(b){b&&a._saveItem(a.CONSTANTS.STORAGE.ANGULAR_LOGIN_REQUEST,b),a.config&&a.config.localLoginUrl?(a.info("Login event for:"+a.config.localLoginUrl),g.path(a.config.localLoginUrl)):(a.info("Start login at:"+e.location.href),d.$broadcast("adal:loginRedirect"),a.login())},r=function(c,d){if(d&&d.$$route)if(j(d.$$route,a.config))b.isAuthenticated||a._renewActive||a.loginInProgress()||(a.info("Route change event for:"+g.$$url),q());else{var e;e="function"==typeof d.$$route.templateUrl?d.$$route.templateUrl(d.params):d.$$route.templateUrl,e&&!k(e)&&a.config.anonymousEndpoints.push(e)}},s=function(c,d,e,f,h){if(d)for(var m=l(d),n=null,o=0;o0;var e=a.getCachedUser()||{userName:""};b.userName=e.userName,b.profile=e.profile,b.loginError=a.getLoginError()};this.init=function(b,d){if(!b)throw new Error("You must set configOptions, when calling init");b.isAngular=!0,d&&d.interceptors&&d.interceptors.push("ProtectedResourceInterceptor"),a=new AuthenticationContext(b),c(a.config.loginResource)},this.$get=["$rootScope","$window","$q","$location","$timeout","$injector",function(d,e,f,g,h,i){function j(a,b){return b.requireADLogin?!1!==a.requireADLogin:!!a.requireADLogin}function k(b){if(a.config&&a.config.anonymousEndpoints)for(var c=0;c-1)return!0;return!1}function l(a){var b=null,c=[];if(a.hasOwnProperty("parent"))for(b=a;b;)c.unshift(b),b=i.get("$state").get(b.parent);else for(var d=a.name.split("."),e=0,f=d[0];e0&&a._openedWindows[a._openedWindows.length-1].opener&&a._openedWindows[a._openedWindows.length-1].opener._adalInstance?(a=a._openedWindows[a._openedWindows.length-1].opener._adalInstance,k=!0):e.parent&&e.parent._adalInstance&&(a=e.parent._adalInstance),a.verbose("Processing the hash: "+f);var l=a.getRequestInfo(f);a.saveTokenFromHash(l);var m=l.parameters.access_token||l.parameters.id_token,n=l.parameters.error,o=l.parameters.error_description,p=null,q=a._callBackMappedToRenewStates[l.stateResponse]||a.callback;if(l.stateMatch){if(l.requestType===a.REQUEST_TYPE.RENEW_TOKEN?(p=a.CONSTANTS.ACCESS_TOKEN,a._renewActive=!1,e.parent!==e||a._callBackMappedToRenewStates[l.stateResponse]||(m?d.$broadcast("adal:acquireTokenSuccess",m):n&&o&&d.$broadcast("adal:acquireTokenFailure",o,n))):l.requestType===a.REQUEST_TYPE.LOGIN&&(p=a.CONSTANTS.ID_TOKEN,c(a.config.loginResource),b.userName?(h(function(){c(a.config.loginResource),d.userInfo=b},1),d.$broadcast("adal:loginSuccess",m)):d.$broadcast("adal:loginFailure",o,n)),q&&"function"==typeof q&&q(o,m,n,p),window.parent!==window)return void(j&&j.preventDefault&&j.preventDefault());if(e.parent===window&&!k)if(a.config.navigateToLoginRequestUrl){var r=a._getItem(a.CONSTANTS.STORAGE.LOGIN_REQUEST);void 0!==r&&r&&0!==r.length&&(a.verbose("Redirecting to start page: "+r),!g.$$html5&&r.indexOf("#")>-1&&g.url(r.substring(r.indexOf("#")+1)),e.location.href=r)}else g.$$html5?g.hash(""):g.path("")}else d.$broadcast("adal:stateMismatch",o,n)}else if(c(a.config.loginResource),!b.isAuthenticated&&b.userName&&!a._renewActive){var s=i.get("adalAuthenticationService");s.acquireToken(a.config.loginResource).then(function(a){a&&(b.isAuthenticated=!0)},function(a){var b=a.split("|");d.$broadcast("adal:loginFailure",b[0],b[1])})}},q=function(b){b&&a._saveItem(a.CONSTANTS.STORAGE.ANGULAR_LOGIN_REQUEST,b),a.config&&a.config.localLoginUrl?(a.info("Login event for:"+a.config.localLoginUrl),g.path(a.config.localLoginUrl)):(a.info("Start login at:"+e.location.href),d.$broadcast("adal:loginRedirect"),a.login())},r=function(c,d){if(d&&d.$$route)if(j(d.$$route,a.config))b.isAuthenticated||a._renewActive||a.loginInProgress()||(a.info("Route change event for:"+g.$$url),q());else{var e;e="function"==typeof d.$$route.templateUrl?d.$$route.templateUrl(d.params):d.$$route.templateUrl,e&&!k(e)&&a.config.anonymousEndpoints.push(e)}},s=function(c,d,e,f,h){if(d)for(var m=l(d),n=null,o=0;o-1},AuthenticationContext.prototype.getCachedToken=function(a){if(!this._hasResource(a))return null;var b=this._getItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+a),c=this._getItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+a),d=this.config.expireOffsetSeconds||300;return c&&c>this._now()+d?b:(this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+a,""),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+a,0),null)},AuthenticationContext.prototype.getCachedUser=function(){if(this._user)return this._user;var a=this._getItem(this.CONSTANTS.STORAGE.IDTOKEN);return this._user=this._createUser(a),this._user},AuthenticationContext.prototype.registerCallback=function(a,b,c){this._activeRenewals[b]=a,this._callBacksMappedToRenewStates[a]||(this._callBacksMappedToRenewStates[a]=[]);var d=this;this._callBacksMappedToRenewStates[a].push(c),this._callBackMappedToRenewStates[a]||(this._callBackMappedToRenewStates[a]=function(c,e,f,g){d._activeRenewals[b]=null;for(var h=0;h-1)){var b=this._user.profile.upn.split("@");a+="&domain_hint="+encodeURIComponent(b[b.length-1])}return a},AuthenticationContext.prototype._createUser=function(a){var b=null,c=this._extractIdToken(a);return c&&c.hasOwnProperty("aud")&&(c.aud.toLowerCase()===this.config.clientId.toLowerCase()?(b={userName:"",profile:c},c.hasOwnProperty("upn")?b.userName=c.upn:c.hasOwnProperty("email")&&(b.userName=c.email)):this.warn("IdToken has invalid aud field")),b},AuthenticationContext.prototype._getHash=function(a){return a.indexOf("#/")>-1?a=a.substring(a.indexOf("#/")+2):a.indexOf("#")>-1&&(a=a.substring(1)),a},AuthenticationContext.prototype.isCallback=function(a){a=this._getHash(a);var b=this._deserialize(a);return b.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION)||b.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN)||b.hasOwnProperty(this.CONSTANTS.ID_TOKEN)},AuthenticationContext.prototype.getLoginError=function(){return this._getItem(this.CONSTANTS.STORAGE.LOGIN_ERROR)},AuthenticationContext.prototype.getRequestInfo=function(a){a=this._getHash(a);var b=this._deserialize(a),c={valid:!1,parameters:{},stateMatch:!1,stateResponse:"",requestType:this.REQUEST_TYPE.UNKNOWN};if(b&&(c.parameters=b,b.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION)||b.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN)||b.hasOwnProperty(this.CONSTANTS.ID_TOKEN))){c.valid=!0;var d="";if(!b.hasOwnProperty("state"))return this.warn("No state returned"),c;if(this.verbose("State: "+b.state),d=b.state,c.stateResponse=d,this._matchState(c))return c;if(!c.stateMatch&&window.parent){c.requestType=this._requestType;for(var e=this._renewStates,f=0;f-1&&b+1-1)return null;if(this.config&&this.config.endpoints)for(var c in this.config.endpoints)if(a.indexOf(c)>-1)return this.config.endpoints[c];return a.indexOf("http://")>-1||a.indexOf("https://")>-1?this._getHostFromUri(a)===this._getHostFromUri(this.config.redirectUri)?this.config.loginResource:null:this.config.loginResource},AuthenticationContext.prototype._getHostFromUri=function(a){var b=String(a).replace(/^(https?:)\/\//,"");return b=b.split("/")[0]},AuthenticationContext.prototype.handleWindowCallback=function(a){if(null==a&&(a=window.location.hash),this.isCallback(a)){var b=null,c=!1;this._openedWindows.length>0&&this._openedWindows[this._openedWindows.length-1].opener&&this._openedWindows[this._openedWindows.length-1].opener._adalInstance?(b=this._openedWindows[this._openedWindows.length-1].opener._adalInstance,c=!0):window.parent&&window.parent._adalInstance&&(b=window.parent._adalInstance);var d,e,f=b.getRequestInfo(a),g=null;e=c||window.parent!==window?b._callBackMappedToRenewStates[f.stateResponse]:b.callback,b.info("Returned from redirect url"),b.saveTokenFromHash(f),f.requestType===this.REQUEST_TYPE.RENEW_TOKEN&&window.parent?(window.parent!==window?b.verbose("Window is in iframe, acquiring token silently"):b.verbose("acquiring token interactive in progress"),d=f.parameters[b.CONSTANTS.ACCESS_TOKEN]||f.parameters[b.CONSTANTS.ID_TOKEN],g=b.CONSTANTS.ACCESS_TOKEN):f.requestType===this.REQUEST_TYPE.LOGIN&&(d=f.parameters[b.CONSTANTS.ID_TOKEN],g=b.CONSTANTS.ID_TOKEN);var h=f.parameters[b.CONSTANTS.ERROR_DESCRIPTION],i=f.parameters[b.CONSTANTS.ERROR];try{e&&e(h,d,i,g)}catch(a){b.error("Error occurred in user defined callback function: "+a)}window.parent!==window||c||(b.config.navigateToLoginRequestUrl?window.location.href=b._getItem(b.CONSTANTS.STORAGE.LOGIN_REQUEST):window.location.hash="")}},AuthenticationContext.prototype._getNavigateUrl=function(a,b){var c="common";this.config.tenant&&(c=this.config.tenant);var d=this.instance+c+"/oauth2/authorize"+this._serialize(a,this.config,b)+this._addLibMetadata();return this.info("Navigate url:"+d),d},AuthenticationContext.prototype._extractIdToken=function(a){var b=this._decodeJwt(a);if(!b)return null;try{var c=b.JWSPayload,d=this._base64DecodeStringUrlSafe(c);return d?JSON.parse(d):(this.info("The returned id_token could not be base64 url safe decoded."),null)}catch(a){this.error("The returned id_token could not be decoded",a)}return null},AuthenticationContext.prototype._base64DecodeStringUrlSafe=function(a){return a=a.replace(/-/g,"+").replace(/_/g,"/"),window.atob?decodeURIComponent(escape(window.atob(a))):decodeURIComponent(escape(this._decode(a)))},AuthenticationContext.prototype._decode=function(a){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";a=String(a).replace(/=+$/,"");var c=a.length;if(c%4==1)throw new Error("The token to be decoded is not correctly encoded.");for(var d,e,f,g,h,i,j,k,l="",m=0;m>16&255,j=h>>8&255,l+=String.fromCharCode(i,j);break}if(m+1===c-1){h=d<<18|e<<12,i=h>>16&255,l+=String.fromCharCode(i);break}h=d<<18|e<<12|f<<6|g,i=h>>16&255,j=h>>8&255,k=255&h,l+=String.fromCharCode(i,j,k)}return l},AuthenticationContext.prototype._decodeJwt=function(a){if(this._isEmpty(a))return null;var b=/^([^\.\s]*)\.([^\.\s]+)\.([^\.\s]*)$/,c=b.exec(a);return!c||c.length<4?(this.warn("The returned id_token is not parseable."),null):{header:c[1],JWSPayload:c[2],JWSSig:c[3]}},AuthenticationContext.prototype._convertUrlSafeToRegularBase64EncodedString=function(a){return a.replace("-","+").replace("_","/")},AuthenticationContext.prototype._serialize=function(a,b,c){var d=[];if(null!==b){d.push("?response_type="+a),d.push("client_id="+encodeURIComponent(b.clientId)),c&&d.push("resource="+encodeURIComponent(c)),d.push("redirect_uri="+encodeURIComponent(b.redirectUri)),d.push("state="+encodeURIComponent(b.state)),b.hasOwnProperty("slice")&&d.push("slice="+encodeURIComponent(b.slice)),b.hasOwnProperty("extraQueryParameter")&&d.push(b.extraQueryParameter);var e=b.correlationId?b.correlationId:this._guid();d.push("client-request-id="+encodeURIComponent(e))}return d.join("&")},AuthenticationContext.prototype._deserialize=function(a){var b,c=/\+/g,d=/([^&=]+)=([^&]*)/g,e=function(a){return decodeURIComponent(a.replace(c," "))},f={};for(b=d.exec(a);b;)f[e(b[1])]=e(b[2]),b=d.exec(a);return f},AuthenticationContext.prototype._decimalToHex=function(a){for(var b=a.toString(16);b.length<2;)b="0"+b;return b},AuthenticationContext.prototype._guid=function(){var a=window.crypto||window.msCrypto;if(a&&a.getRandomValues){var b=new Uint8Array(16);return a.getRandomValues(b),b[6]|=64,b[6]&=79,b[8]|=128,b[8]&=191,this._decimalToHex(b[0])+this._decimalToHex(b[1])+this._decimalToHex(b[2])+this._decimalToHex(b[3])+"-"+this._decimalToHex(b[4])+this._decimalToHex(b[5])+"-"+this._decimalToHex(b[6])+this._decimalToHex(b[7])+"-"+this._decimalToHex(b[8])+this._decimalToHex(b[9])+"-"+this._decimalToHex(b[10])+this._decimalToHex(b[11])+this._decimalToHex(b[12])+this._decimalToHex(b[13])+this._decimalToHex(b[14])+this._decimalToHex(b[15])}for(var c="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx",d="0123456789abcdef",e=0,f="",g=0;g<36;g++)"-"!==c[g]&&"4"!==c[g]&&(e=16*Math.random()|0),"x"===c[g]?f+=d[e]:"y"===c[g]?(e&=3,e|=8,f+=d[e]):f+=c[g];return f},AuthenticationContext.prototype._expiresIn=function(a){return a||(a=3599),this._now()+parseInt(a,10)},AuthenticationContext.prototype._now=function(){return Math.round((new Date).getTime()/1e3)},AuthenticationContext.prototype._addAdalFrame=function(a){if(void 0!==a){this.info("Add adal frame to document:"+a);var b=document.getElementById(a);if(!b){if(document.createElement&&document.documentElement&&(window.opera||-1===window.navigator.userAgent.indexOf("MSIE 5.0"))){var c=document.createElement("iframe");c.setAttribute("id",a),c.setAttribute("aria-hidden","true"),c.style.visibility="hidden",c.style.position="absolute",c.style.width=c.style.height=c.borderWidth="0px",b=document.getElementsByTagName("body")[0].appendChild(c)}else document.body&&document.body.insertAdjacentHTML&&document.body.insertAdjacentHTML("beforeEnd",'');window.frames&&window.frames[a]&&(b=window.frames[a])}return b}},AuthenticationContext.prototype._saveItem=function(a,b,c){if(this.config&&this.config.cacheLocation&&"localStorage"===this.config.cacheLocation){if(!this._supportsLocalStorage())return this.info("Local storage is not supported"),!1;if(c){var d=this._getItem(a)||"";localStorage.setItem(a,d+b+this.CONSTANTS.CACHE_DELIMETER)}else localStorage.setItem(a,b);return!0}return this._supportsSessionStorage()?(sessionStorage.setItem(a,b),!0):(this.info("Session storage is not supported"),!1)},AuthenticationContext.prototype._getItem=function(a){return this.config&&this.config.cacheLocation&&"localStorage"===this.config.cacheLocation?this._supportsLocalStorage()?localStorage.getItem(a):(this.info("Local storage is not supported"),null):this._supportsSessionStorage()?sessionStorage.getItem(a):(this.info("Session storage is not supported"),null)},AuthenticationContext.prototype._supportsLocalStorage=function(){try{return!!window.localStorage&&(window.localStorage.setItem("storageTest","A"),"A"==window.localStorage.getItem("storageTest")&&(window.localStorage.removeItem("storageTest"),!window.localStorage.getItem("storageTest")))}catch(a){return!1}},AuthenticationContext.prototype._supportsSessionStorage=function(){try{return!!window.sessionStorage&&(window.sessionStorage.setItem("storageTest","A"),"A"==window.sessionStorage.getItem("storageTest")&&(window.sessionStorage.removeItem("storageTest"),!window.sessionStorage.getItem("storageTest")))}catch(a){return!1}},AuthenticationContext.prototype._cloneConfig=function(a){if(null===a||"object"!=typeof a)return a;var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},AuthenticationContext.prototype._addLibMetadata=function(){return"&x-client-SKU=Js&x-client-Ver="+this._libVersion()},AuthenticationContext.prototype.log=function(a,b,c,d){if(a<=Logging.level){if(!Logging.piiLoggingEnabled&&d)return;var e=(new Date).toUTCString(),f="";f=this.config.correlationId?e+":"+this.config.correlationId+"-"+this._libVersion()+"-"+this.CONSTANTS.LEVEL_STRING_MAP[a]+" "+b:e+":"+this._libVersion()+"-"+this.CONSTANTS.LEVEL_STRING_MAP[a]+" "+b,c&&(f+="\nstack:\n"+c.stack),Logging.log(f)}},AuthenticationContext.prototype.error=function(a,b){this.log(this.CONSTANTS.LOGGING_LEVEL.ERROR,a,b)},AuthenticationContext.prototype.warn=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.WARN,a,null)},AuthenticationContext.prototype.info=function(a){ -this.log(this.CONSTANTS.LOGGING_LEVEL.INFO,a,null)},AuthenticationContext.prototype.verbose=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.VERBOSE,a,null)},AuthenticationContext.prototype.errorPii=function(a,b){this.log(this.CONSTANTS.LOGGING_LEVEL.ERROR,a,b,!0)},AuthenticationContext.prototype.warnPii=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.WARN,a,null,!0)},AuthenticationContext.prototype.infoPii=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.INFO,a,null,!0)},AuthenticationContext.prototype.verbosePii=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.VERBOSE,a,null,!0)},AuthenticationContext.prototype._libVersion=function(){return"1.0.17"},"undefined"!=typeof module&&module.exports&&(module.exports=AuthenticationContext,module.exports.inject=function(a){return new AuthenticationContext(a)}),AuthenticationContext}(); \ No newline at end of file +/*! adal-angular v1.0.18 2018-11-29 */ +var AuthenticationContext=function(){"use strict";return AuthenticationContext=function(a){if(this.REQUEST_TYPE={LOGIN:"LOGIN",RENEW_TOKEN:"RENEW_TOKEN",UNKNOWN:"UNKNOWN"},this.RESPONSE_TYPE={ID_TOKEN_TOKEN:"id_token token",TOKEN:"token"},this.CONSTANTS={ACCESS_TOKEN:"access_token",EXPIRES_IN:"expires_in",ID_TOKEN:"id_token",ERROR_DESCRIPTION:"error_description",SESSION_STATE:"session_state",ERROR:"error",STORAGE:{TOKEN_KEYS:"adal.token.keys",ACCESS_TOKEN_KEY:"adal.access.token.key",EXPIRATION_KEY:"adal.expiration.key",STATE_LOGIN:"adal.state.login",STATE_RENEW:"adal.state.renew",NONCE_IDTOKEN:"adal.nonce.idtoken",SESSION_STATE:"adal.session.state",USERNAME:"adal.username",IDTOKEN:"adal.idtoken",ERROR:"adal.error",ERROR_DESCRIPTION:"adal.error.description",LOGIN_REQUEST:"adal.login.request",LOGIN_ERROR:"adal.login.error",RENEW_STATUS:"adal.token.renew.status",ANGULAR_LOGIN_REQUEST:"adal.angular.login.request"},RESOURCE_DELIMETER:"|",CACHE_DELIMETER:"||",LOADFRAME_TIMEOUT:6e3,TOKEN_RENEW_STATUS_CANCELED:"Canceled",TOKEN_RENEW_STATUS_COMPLETED:"Completed",TOKEN_RENEW_STATUS_IN_PROGRESS:"In Progress",LOGGING_LEVEL:{ERROR:0,WARN:1,INFO:2,VERBOSE:3},LEVEL_STRING_MAP:{0:"ERROR:",1:"WARNING:",2:"INFO:",3:"VERBOSE:"},POPUP_WIDTH:483,POPUP_HEIGHT:600},AuthenticationContext.prototype._singletonInstance)return AuthenticationContext.prototype._singletonInstance;if(AuthenticationContext.prototype._singletonInstance=this,this.instance="https://login.microsoftonline.com/",this.config={},this.callback=null,this.popUp=!1,this.isAngular=!1,this._user=null,this._activeRenewals={},this._loginInProgress=!1,this._acquireTokenInProgress=!1,this._renewStates=[],this._callBackMappedToRenewStates={},this._callBacksMappedToRenewStates={},this._openedWindows=[],this._requestType=this.REQUEST_TYPE.LOGIN,window._adalInstance=this,this._storageSupport={localStorage:null,sessionStorage:null},a.displayCall&&"function"!=typeof a.displayCall)throw new Error("displayCall is not a function");if(!a.clientId)throw new Error("clientId is required");this.config=this._cloneConfig(a),void 0===this.config.navigateToLoginRequestUrl&&(this.config.navigateToLoginRequestUrl=!0),this.config.popUp&&(this.popUp=!0),this.config.callback&&"function"==typeof this.config.callback&&(this.callback=this.config.callback),this.config.instance&&(this.instance=this.config.instance),this.config.loginResource||(this.config.loginResource=this.config.clientId),this.config.redirectUri||(this.config.redirectUri=window.location.href.split("?")[0].split("#")[0]),this.config.postLogoutRedirectUri||(this.config.postLogoutRedirectUri=window.location.href.split("?")[0].split("#")[0]),this.config.anonymousEndpoints||(this.config.anonymousEndpoints=[]),this.config.isAngular&&(this.isAngular=this.config.isAngular),this.config.loadFrameTimeout&&(this.CONSTANTS.LOADFRAME_TIMEOUT=this.config.loadFrameTimeout)},"undefined"!=typeof window&&(window.Logging={piiLoggingEnabled:!1,level:0,log:function(a){}}),AuthenticationContext.prototype.login=function(){if(this._loginInProgress)return void this.info("Login in progress");this._loginInProgress=!0;var a=this._guid();this.config.state=a,this._idTokenNonce=this._guid();var b=this._getItem(this.CONSTANTS.STORAGE.ANGULAR_LOGIN_REQUEST);b&&""!==b?this._saveItem(this.CONSTANTS.STORAGE.ANGULAR_LOGIN_REQUEST,""):b=window.location.href,this.verbose("Expected state: "+a+" startPage:"+b),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST,b),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN,a,!0),this._saveItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN,this._idTokenNonce,!0),this._saveItem(this.CONSTANTS.STORAGE.ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,"");var c=this._getNavigateUrl("id_token",null)+"&nonce="+encodeURIComponent(this._idTokenNonce);this.config.displayCall?this.config.displayCall(c):this.popUp?(this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN,""),this._renewStates.push(a),this.registerCallback(a,this.config.clientId,this.callback),this._loginPopup(c)):this.promptUser(c)},AuthenticationContext.prototype._openPopup=function(a,b,c,d){try{var e=window.screenLeft?window.screenLeft:window.screenX,f=window.screenTop?window.screenTop:window.screenY,g=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,h=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight,i=g/2-c/2+e,j=h/2-d/2+f,k=window.open(a,b,"width="+c+", height="+d+", top="+j+", left="+i);return k.focus&&k.focus(),k}catch(a){return this.warn("Error opening popup, "+a.message),this._loginInProgress=!1,this._acquireTokenInProgress=!1,null}},AuthenticationContext.prototype._handlePopupError=function(a,b,c,d,e){this.warn(d),this._saveItem(this.CONSTANTS.STORAGE.ERROR,c),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,d),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR,e),b&&this._activeRenewals[b]&&(this._activeRenewals[b]=null),this._loginInProgress=!1,this._acquireTokenInProgress=!1,a&&a(d,null,c)},AuthenticationContext.prototype._loginPopup=function(a,b,c){var d=this._openPopup(a,"login",this.CONSTANTS.POPUP_WIDTH,this.CONSTANTS.POPUP_HEIGHT),e=c||this.callback;if(null==d){var f="Popup Window is null. This can happen if you are using IE";return void this._handlePopupError(e,b,"Error opening popup",f,f)}if(this._openedWindows.push(d),-1!=this.config.redirectUri.indexOf("#"))var g=this.config.redirectUri.split("#")[0];else var g=this.config.redirectUri;var h=this,i=window.setInterval(function(){if(!d||d.closed||void 0===d.closed){var a="Popup Window closed",c="Popup Window closed by UI action/ Popup Window handle destroyed due to cross zone navigation in IE/Edge";return h.isAngular&&h._broadcast("adal:popUpClosed",c+h.CONSTANTS.RESOURCE_DELIMETER+a),h._handlePopupError(e,b,a,c,c),void window.clearInterval(i)}try{var f=d.location;if(-1!=encodeURI(f.href).indexOf(encodeURI(g)))return h.isAngular?h._broadcast("adal:popUpHashChanged",f.hash):h.handleWindowCallback(f.hash),window.clearInterval(i),h._loginInProgress=!1,h._acquireTokenInProgress=!1,h.info("Closing popup window"),h._openedWindows=[],void d.close()}catch(a){}},1)},AuthenticationContext.prototype._broadcast=function(a,b){!function(){function a(a,b){b=b||{bubbles:!1,cancelable:!1,detail:void 0};var c=document.createEvent("CustomEvent");return c.initCustomEvent(a,b.bubbles,b.cancelable,b.detail),c}if("function"==typeof window.CustomEvent)return!1;a.prototype=window.Event.prototype,window.CustomEvent=a}();var c=new CustomEvent(a,{detail:b});window.dispatchEvent(c)},AuthenticationContext.prototype.loginInProgress=function(){return this._loginInProgress},AuthenticationContext.prototype._hasResource=function(a){var b=this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS);return b&&!this._isEmpty(b)&&b.indexOf(a+this.CONSTANTS.RESOURCE_DELIMETER)>-1},AuthenticationContext.prototype.getCachedToken=function(a){if(!this._hasResource(a))return null;var b=this._getItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+a),c=this._getItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+a),d=this.config.expireOffsetSeconds||300;return c&&c>this._now()+d?b:(this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+a,""),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+a,0),null)},AuthenticationContext.prototype.getCachedUser=function(){if(this._user)return this._user;var a=this._getItem(this.CONSTANTS.STORAGE.IDTOKEN);return this._user=this._createUser(a),this._user},AuthenticationContext.prototype.registerCallback=function(a,b,c){this._activeRenewals[b]=a,this._callBacksMappedToRenewStates[a]||(this._callBacksMappedToRenewStates[a]=[]);var d=this;this._callBacksMappedToRenewStates[a].push(c),this._callBackMappedToRenewStates[a]||(this._callBackMappedToRenewStates[a]=function(c,e,f,g){d._activeRenewals[b]=null;for(var h=0;h-1)){var b=this._user.profile.upn.split("@");a+="&domain_hint="+encodeURIComponent(b[b.length-1])}return a},AuthenticationContext.prototype._createUser=function(a){var b=null,c=this._extractIdToken(a);return c&&c.hasOwnProperty("aud")&&(c.aud.toLowerCase()===this.config.clientId.toLowerCase()?(b={userName:"",profile:c},c.hasOwnProperty("upn")?b.userName=c.upn:c.hasOwnProperty("email")&&(b.userName=c.email)):this.warn("IdToken has invalid aud field")),b},AuthenticationContext.prototype._getHash=function(a){return a.indexOf("#/")>-1?a=a.substring(a.indexOf("#/")+2):a.indexOf("#")>-1&&(a=a.substring(1)),a},AuthenticationContext.prototype.isCallback=function(a){a=this._getHash(a);var b=this._deserialize(a);return b.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION)||b.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN)||b.hasOwnProperty(this.CONSTANTS.ID_TOKEN)},AuthenticationContext.prototype.getLoginError=function(){return this._getItem(this.CONSTANTS.STORAGE.LOGIN_ERROR)},AuthenticationContext.prototype.getRequestInfo=function(a){a=this._getHash(a);var b=this._deserialize(a),c={valid:!1,parameters:{},stateMatch:!1,stateResponse:"",requestType:this.REQUEST_TYPE.UNKNOWN};if(b&&(c.parameters=b,b.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION)||b.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN)||b.hasOwnProperty(this.CONSTANTS.ID_TOKEN))){c.valid=!0;var d="";if(!b.hasOwnProperty("state"))return this.warn("No state returned"),c;if(this.verbose("State: "+b.state),d=b.state,c.stateResponse=d,this._matchState(c))return c;if(!c.stateMatch&&window.parent){c.requestType=this._requestType;for(var e=this._renewStates,f=0;f-1&&b+1-1)return null;if(this.config&&this.config.endpoints)for(var c in this.config.endpoints)if(a.indexOf(c)>-1)return this.config.endpoints[c];return a.indexOf("http://")>-1||a.indexOf("https://")>-1?this._getHostFromUri(a)===this._getHostFromUri(this.config.redirectUri)?this.config.loginResource:null:this.config.loginResource},AuthenticationContext.prototype._getHostFromUri=function(a){var b=String(a).replace(/^(https?:)\/\//,"");return b=b.split("/")[0]},AuthenticationContext.prototype.handleWindowCallback=function(a){if(null==a&&(a=window.location.hash),this.isCallback(a)){var b=null,c=!1;this._openedWindows.length>0&&this._openedWindows[this._openedWindows.length-1].opener&&this._openedWindows[this._openedWindows.length-1].opener._adalInstance?(b=this._openedWindows[this._openedWindows.length-1].opener._adalInstance,c=!0):window.parent&&window.parent._adalInstance&&(b=window.parent._adalInstance);var d,e,f=b.getRequestInfo(a),g=null;e=c||window.parent!==window?b._callBackMappedToRenewStates[f.stateResponse]:b.callback,b.info("Returned from redirect url"),b.saveTokenFromHash(f),f.requestType===this.REQUEST_TYPE.RENEW_TOKEN&&window.parent?(window.parent!==window?b.verbose("Window is in iframe, acquiring token silently"):b.verbose("acquiring token interactive in progress"),d=f.parameters[b.CONSTANTS.ACCESS_TOKEN]||f.parameters[b.CONSTANTS.ID_TOKEN],g=b.CONSTANTS.ACCESS_TOKEN):f.requestType===this.REQUEST_TYPE.LOGIN&&(d=f.parameters[b.CONSTANTS.ID_TOKEN],g=b.CONSTANTS.ID_TOKEN);var h=f.parameters[b.CONSTANTS.ERROR_DESCRIPTION],i=f.parameters[b.CONSTANTS.ERROR];try{e&&e(h,d,i,g)}catch(a){b.error("Error occurred in user defined callback function: "+a)}window.parent!==window||c||(b.config.navigateToLoginRequestUrl?window.location.href=b._getItem(b.CONSTANTS.STORAGE.LOGIN_REQUEST):window.location.hash="")}},AuthenticationContext.prototype._getNavigateUrl=function(a,b){var c="common";this.config.tenant&&(c=this.config.tenant);var d=this.instance+c+"/oauth2/authorize"+this._serialize(a,this.config,b)+this._addLibMetadata();return this.info("Navigate url:"+d),d},AuthenticationContext.prototype._extractIdToken=function(a){var b=this._decodeJwt(a);if(!b)return null;try{var c=b.JWSPayload,d=this._base64DecodeStringUrlSafe(c);return d?JSON.parse(d):(this.info("The returned id_token could not be base64 url safe decoded."),null)}catch(a){this.error("The returned id_token could not be decoded",a)}return null},AuthenticationContext.prototype._base64DecodeStringUrlSafe=function(a){return a=a.replace(/-/g,"+").replace(/_/g,"/"),window.atob?decodeURIComponent(escape(window.atob(a))):decodeURIComponent(escape(this._decode(a)))},AuthenticationContext.prototype._decode=function(a){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";a=String(a).replace(/=+$/,"");var c=a.length;if(c%4==1)throw new Error("The token to be decoded is not correctly encoded.");for(var d,e,f,g,h,i,j,k,l="",m=0;m>16&255,j=h>>8&255,l+=String.fromCharCode(i,j);break}if(m+1===c-1){h=d<<18|e<<12,i=h>>16&255,l+=String.fromCharCode(i);break}h=d<<18|e<<12|f<<6|g,i=h>>16&255,j=h>>8&255,k=255&h,l+=String.fromCharCode(i,j,k)}return l},AuthenticationContext.prototype._decodeJwt=function(a){if(this._isEmpty(a))return null;var b=/^([^\.\s]*)\.([^\.\s]+)\.([^\.\s]*)$/,c=b.exec(a);return!c||c.length<4?(this.warn("The returned id_token is not parseable."),null):{header:c[1],JWSPayload:c[2],JWSSig:c[3]}},AuthenticationContext.prototype._convertUrlSafeToRegularBase64EncodedString=function(a){return a.replace("-","+").replace("_","/")},AuthenticationContext.prototype._serialize=function(a,b,c){var d=[];if(null!==b){d.push("?response_type="+a),d.push("client_id="+encodeURIComponent(b.clientId)),c&&d.push("resource="+encodeURIComponent(c)),d.push("redirect_uri="+encodeURIComponent(b.redirectUri)),d.push("state="+encodeURIComponent(b.state)),b.hasOwnProperty("slice")&&d.push("slice="+encodeURIComponent(b.slice)),b.hasOwnProperty("extraQueryParameter")&&d.push(b.extraQueryParameter);var e=b.correlationId?b.correlationId:this._guid();d.push("client-request-id="+encodeURIComponent(e))}return d.join("&")},AuthenticationContext.prototype._deserialize=function(a){var b,c=/\+/g,d=/([^&=]+)=([^&]*)/g,e=function(a){return decodeURIComponent(a.replace(c," "))},f={};for(b=d.exec(a);b;)f[e(b[1])]=e(b[2]),b=d.exec(a);return f},AuthenticationContext.prototype._decimalToHex=function(a){for(var b=a.toString(16);b.length<2;)b="0"+b;return b},AuthenticationContext.prototype._guid=function(){var a=window.crypto||window.msCrypto;if(a&&a.getRandomValues){var b=new Uint8Array(16);return a.getRandomValues(b),b[6]|=64,b[6]&=79,b[8]|=128,b[8]&=191,this._decimalToHex(b[0])+this._decimalToHex(b[1])+this._decimalToHex(b[2])+this._decimalToHex(b[3])+"-"+this._decimalToHex(b[4])+this._decimalToHex(b[5])+"-"+this._decimalToHex(b[6])+this._decimalToHex(b[7])+"-"+this._decimalToHex(b[8])+this._decimalToHex(b[9])+"-"+this._decimalToHex(b[10])+this._decimalToHex(b[11])+this._decimalToHex(b[12])+this._decimalToHex(b[13])+this._decimalToHex(b[14])+this._decimalToHex(b[15])}for(var c="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx",d="0123456789abcdef",e=0,f="",g=0;g<36;g++)"-"!==c[g]&&"4"!==c[g]&&(e=16*Math.random()|0),"x"===c[g]?f+=d[e]:"y"===c[g]?(e&=3,e|=8,f+=d[e]):f+=c[g];return f},AuthenticationContext.prototype._expiresIn=function(a){return a||(a=3599),this._now()+parseInt(a,10)},AuthenticationContext.prototype._now=function(){return Math.round((new Date).getTime()/1e3)},AuthenticationContext.prototype._addAdalFrame=function(a){if(void 0!==a){this.info("Add adal frame to document:"+a);var b=document.getElementById(a);if(!b){if(document.createElement&&document.documentElement&&(window.opera||-1===window.navigator.userAgent.indexOf("MSIE 5.0"))){var c=document.createElement("iframe");c.setAttribute("id",a),c.setAttribute("aria-hidden","true"),c.style.visibility="hidden",c.style.position="absolute",c.style.width=c.style.height=c.style.borderWidth="0px",b=document.getElementsByTagName("body")[0].appendChild(c)}else document.body&&document.body.insertAdjacentHTML&&document.body.insertAdjacentHTML("beforeEnd",'');window.frames&&window.frames[a]&&(b=window.frames[a])}return b}},AuthenticationContext.prototype._saveItem=function(a,b,c){if(this.config&&this.config.cacheLocation&&"localStorage"===this.config.cacheLocation){if(!this._supportsLocalStorage())return this.info("Local storage is not supported"),!1;if(c){var d=this._getItem(a)||"";localStorage.setItem(a,d+b+this.CONSTANTS.CACHE_DELIMETER)}else localStorage.setItem(a,b);return!0}return this._supportsSessionStorage()?(sessionStorage.setItem(a,b),!0):(this.info("Session storage is not supported"),!1)},AuthenticationContext.prototype._getItem=function(a){return this.config&&this.config.cacheLocation&&"localStorage"===this.config.cacheLocation?this._supportsLocalStorage()?localStorage.getItem(a):(this.info("Local storage is not supported"),null):this._supportsSessionStorage()?sessionStorage.getItem(a):(this.info("Session storage is not supported"),null)},AuthenticationContext.prototype._supportsStorage=function(a){if(!(a in this._storageSupport))return!1;if(null!==this._storageSupport[a])return this._storageSupport[a];try{if(!(a in window)||null===window[a])throw new Error;var b="__storageTest__";if(window[a].setItem(b,"A"),"A"!==window[a].getItem(b))throw new Error;if(window[a].removeItem(b),window[a].getItem(b))throw new Error;this._storageSupport[a]=!0}catch(b){this._storageSupport[a]=!1}return this._storageSupport[a]},AuthenticationContext.prototype._supportsLocalStorage=function(){return this._supportsStorage("localStorage")},AuthenticationContext.prototype._supportsSessionStorage=function(){return this._supportsStorage("sessionStorage")},AuthenticationContext.prototype._cloneConfig=function(a){if(null===a||"object"!=typeof a)return a;var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},AuthenticationContext.prototype._addLibMetadata=function(){return"&x-client-SKU=Js&x-client-Ver="+this._libVersion()},AuthenticationContext.prototype.log=function(a,b,c,d){if(a<=Logging.level){if(!Logging.piiLoggingEnabled&&d)return;var e=(new Date).toUTCString(),f="";f=this.config.correlationId?e+":"+this.config.correlationId+"-"+this._libVersion()+"-"+this.CONSTANTS.LEVEL_STRING_MAP[a]+" "+b:e+":"+this._libVersion()+"-"+this.CONSTANTS.LEVEL_STRING_MAP[a]+" "+b,c&&(f+="\nstack:\n"+c.stack),Logging.log(f)}},AuthenticationContext.prototype.error=function(a,b){this.log(this.CONSTANTS.LOGGING_LEVEL.ERROR,a,b)}, +AuthenticationContext.prototype.warn=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.WARN,a,null)},AuthenticationContext.prototype.info=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.INFO,a,null)},AuthenticationContext.prototype.verbose=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.VERBOSE,a,null)},AuthenticationContext.prototype.errorPii=function(a,b){this.log(this.CONSTANTS.LOGGING_LEVEL.ERROR,a,b,!0)},AuthenticationContext.prototype.warnPii=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.WARN,a,null,!0)},AuthenticationContext.prototype.infoPii=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.INFO,a,null,!0)},AuthenticationContext.prototype.verbosePii=function(a){this.log(this.CONSTANTS.LOGGING_LEVEL.VERBOSE,a,null,!0)},AuthenticationContext.prototype._libVersion=function(){return"1.0.18"},"undefined"!=typeof module&&module.exports&&(module.exports=AuthenticationContext,module.exports.inject=function(a){return new AuthenticationContext(a)}),AuthenticationContext}(); \ No newline at end of file From cf68ea4eca54855937ce5962c786733a90935c3f Mon Sep 17 00:00:00 2001 From: nehaagrawal Date: Thu, 29 Nov 2018 16:02:16 -0800 Subject: [PATCH 26/36] updated atob version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f3f42646..f7b24626 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "grunt-contrib-uglify": "~0.6.0", "grunt-contrib-watch": "~0.2.0", "grunt-karma": "^0.9.x", - "atob": "~1.1.2", + "atob": ">=2.1.0", "karma-chrome-launcher": "^0.1.5", "karma": "^0.12.24", "karma-jasmine": "^0.1.5", From 180e87a7366873afc3e551ac7ecf68771d6a7140 Mon Sep 17 00:00:00 2001 From: wenYorker Date: Fri, 30 Nov 2018 13:44:39 -0800 Subject: [PATCH 27/36] changed >= to ~ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f7b24626..8a709edc 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "grunt-contrib-uglify": "~0.6.0", "grunt-contrib-watch": "~0.2.0", "grunt-karma": "^0.9.x", - "atob": ">=2.1.0", + "atob": "~2.1.0", "karma-chrome-launcher": "^0.1.5", "karma": "^0.12.24", "karma-jasmine": "^0.1.5", From 473b668b642231adb367dd49137424c1c534ede2 Mon Sep 17 00:00:00 2001 From: sameerag Date: Mon, 3 Dec 2018 17:11:12 -0800 Subject: [PATCH 28/36] Reverse the Circular reference error fix for a more comprehensive fix later --- lib/adal-angular.js | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/lib/adal-angular.js b/lib/adal-angular.js index 8cd43b68..39d6906a 100644 --- a/lib/adal-angular.js +++ b/lib/adal-angular.js @@ -315,7 +315,7 @@ }; var stateChangeErrorHandler = function (event, toState, toParams, fromState, fromParams, error) { - _adal.verbose("State change error occured. Error: " + typeof (error) === 'string' ? error : JSON.stringify(error, jsonCircularReferenceReplacer())); + _adal.verbose("State change error occured. Error: " + typeof (error) === 'string' ? error : JSON.stringify(error)); // adal interceptor sets the error on config.data property. If it is set, it means state change is rejected by adal, // in which case set the defaultPrevented to true to avoid url update as that sometimesleads to infinte loop. if (error && error.data) { @@ -325,19 +325,6 @@ } }; - var jsonCircularReferenceReplacer = function () { - var cache = []; - return function (key, value) { - if (typeof value === "object" && value !== null) { - if (cache.indexOf(value) !== -1) { - return; - } - cache.push(value); - } - return value; - }; - } - if ($injector.has('$transitions')) { var $transitions = $injector.get('$transitions'); @@ -540,7 +527,7 @@ } }, responseError: function (rejection) { - authService.info('Getting error in the response: ' + JSON.stringify(rejection, jsonCircularReferenceReplacer())); + authService.info('Getting error in the response: ' + JSON.stringify(rejection)); if (rejection) { if (rejection.status === 401) { var resource = authService.getResourceForEndpoint(rejection.config.url); From 2db550f2f1692be0120e524c467c2bb3fac0aa4f Mon Sep 17 00:00:00 2001 From: Bernard Vander Beken Date: Mon, 24 Jun 2019 11:28:15 +0200 Subject: [PATCH 29/36] Fix markdown syntax --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02393d60..17a1db7b 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ function callbackFunction(errorDesc, token, error, tokenType) #### 2. Login the user -Your app must login the user to establish user context. The login operates in popup mode if you set the option `popUp: true` instead of a full redirect as shown in the config above.Defaults to `false. The callback function passed in the Authentication request constructor will be called after the login with success or failure results. +Your app must login the user to establish user context. The login operates in popup mode if you set the option `popUp: true` instead of a full redirect as shown in the config above. Defaults to `false`. The callback function passed in the Authentication request constructor will be called after the login with success or failure results. ```JavaScript var user = authenticationContext.getCachedUser(); From 63032182ddd74b8fc9466b32cd11660245a6d6ad Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 17 Sep 2019 15:32:25 -0700 Subject: [PATCH 30/36] Fix #862, use CDN links for latest release Fixes #862 . This updates the library's CDN links so that they use the latest available release (at the time of committing). These links were changed in 0239b400a2048aa8a8763fa18e068a69219441f6, which appears to have been copied/cherry-picked from the dev branch where 1.0.18 is being worked on (PR #839 ). Since this release is not out yet, and these links 404, they have been updated to use the latest release of the library (1.0.17). --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 17a1db7b..8741993e 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,8 @@ Via NPM (https://www.npmjs.com/package/adal-angular): Via CDN: - - + + Via Bower: From b9d73e3569a434f63c66efeb43f169bf8e4d9b7e Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 17 Sep 2019 15:35:14 -0700 Subject: [PATCH 31/36] Rollback version number to 1.0.17 in readme While I'm at it, rollback the current version number to be 1.0.17 in the readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8741993e..d43fe4ca 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ You can learn further details about ADAL.js functionality documented in the [ADA ## Versions -Current version - **1.0.18** +Current version - **1.0.17** Minimum recommended version - 1.0.11 You can find the changes for each version in the [change log](https://github.com/AzureAD/azure-activedirectory-library-for-js/blob/master/changelog.txt). From 9c9231b6454b16c261af72c9db74b84cf0bb9651 Mon Sep 17 00:00:00 2001 From: Aisha Wang Date: Tue, 11 Feb 2020 14:53:11 -0800 Subject: [PATCH 32/36] Added ADAL announcement No new features, only security fixes for ADAL for JavaScript --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index d43fe4ca..ca29812c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,18 @@ +--- + +This library, ADAL for JavaScript, will no longer receive new feature improvements. Instead, use the new +[MSAL.js](https://github.com/AzureAD/microsoft-authentication-library-for-js). + +* If you are starting a new project, you can get started with the + [MSAL.js docs](https://github.com/AzureAD/microsoft-authentication-library-for-js/wiki) + for details about the scenarios, usage, and relevant concepts. +* If your application is using the previous ADAL JavaScript library, you can follow this + [migration guide](https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-compare-msal-js-and-adal-js) + to update to MSAL.js. +* Existing applications relying on ADAL JavaScript will continue to work. + +--- + Active Directory Authentication Library (ADAL) for JavaScript ==================================== |[Getting Started](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki)| [Docs](https://aka.ms/aaddev)| [Samples](https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/Code-samples)| [Support](README.md#community-help-and-support) From 463f0c71c7e0bc1a17d7d59a24b40e2cf75c4afa Mon Sep 17 00:00:00 2001 From: Aisha Wang Date: Tue, 11 Feb 2020 14:56:07 -0800 Subject: [PATCH 33/36] Nit update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca29812c..83f9b76a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ --- -This library, ADAL for JavaScript, will no longer receive new feature improvements. Instead, use the new +This library, ADAL for JavaScript, will no longer receive new feature improvements. Instead, use the new library [MSAL.js](https://github.com/AzureAD/microsoft-authentication-library-for-js). * If you are starting a new project, you can get started with the From fe0e7037500f481412c7a015dac2e553b99dc51a Mon Sep 17 00:00:00 2001 From: Aisha Wang Date: Tue, 11 Feb 2020 15:08:39 -0800 Subject: [PATCH 34/36] Updated for localization --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83f9b76a..bd62195e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This library, ADAL for JavaScript, will no longer receive new feature improvemen [MSAL.js docs](https://github.com/AzureAD/microsoft-authentication-library-for-js/wiki) for details about the scenarios, usage, and relevant concepts. * If your application is using the previous ADAL JavaScript library, you can follow this - [migration guide](https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-compare-msal-js-and-adal-js) + [migration guide](https://docs.microsoft.com/azure/active-directory/develop/msal-compare-msal-js-and-adal-js) to update to MSAL.js. * Existing applications relying on ADAL JavaScript will continue to work. From 796d1a253104f45883d04556cb70ff8043d41fff Mon Sep 17 00:00:00 2001 From: Gang Peng Date: Thu, 27 Feb 2020 15:38:59 -0800 Subject: [PATCH 35/36] Fix issue that ADAL mistakenly set token expiration time in local storage What: ADAL has this issue that it will update 'adal.expiration.key' based on current local time + expires_in info from AAD, however, if the callback is not executed on time due to all kinds of reasons, such as browser tabs are inactive or computer is sleeping, then it may get into this state that token expiration time is mistakenly set. How: To fix the issue, when ADAL requests AAD access token, it will pass its current local time in the "state" query parameter, which will be returned by AAD on success, and we will use the passed in local time in "state" to calculate the correct token expiration time and set it to "adal.expiration.key" inside local storage. --- lib/adal.js | 34 +++++++++++++++++++++++++++------- tests/unit/spec/AdalSpec.js | 25 +++++++++++++++++++------ 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/lib/adal.js b/lib/adal.js index 5e9a074b..da53d544 100644 --- a/lib/adal.js +++ b/lib/adal.js @@ -498,7 +498,7 @@ var AuthenticationContext = (function () { // use given resource to create new authz url this.info('renewToken is called for resource:' + resource); var frameHandle = this._addAdalFrame('adalRenewFrame' + resource); - var expectedState = this._guid() + '|' + resource; + var expectedState = this._guid() + '|' + resource + '|' + this._now(); this.config.state = expectedState; // renew happens in iframe, so it keeps javascript context this._renewStates.push(expectedState); @@ -1153,16 +1153,31 @@ var AuthenticationContext = (function () { */ AuthenticationContext.prototype._getResourceFromState = function (state) { if (state) { - var splitIndex = state.indexOf('|'); + var splittedInfo = state.split('|'); - if (splitIndex > -1 && splitIndex + 1 < state.length) { - return state.substring(splitIndex + 1); + if (splittedInfo.length > 1) { + return splittedInfo[1]; } } return ''; }; + /** + * Extracts token expiration base time value from state. + * @ignore + */ + AuthenticationContext.prototype._getExpireBaseTimeFromState = function (state) { + if (state) { + var splittedInfo = state.split('|'); + + if (splittedInfo.length > 2) { + return parseInt(splittedInfo[2], 10); + } + } + return 0; + }; + /** * Saves token or error received in the response from AAD in the cache. In case of id_token, it also creates the user object. */ @@ -1204,7 +1219,7 @@ var AuthenticationContext = (function () { // save token with related resource this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource, requestInfo.parameters[this.CONSTANTS.ACCESS_TOKEN]); - this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, this._expiresIn(requestInfo.parameters[this.CONSTANTS.EXPIRES_IN])); + this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, this._expiresIn(requestInfo.parameters[this.CONSTANTS.EXPIRES_IN], requestInfo.stateResponse)); } if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)) { @@ -1655,10 +1670,15 @@ var AuthenticationContext = (function () { * Calculates the expires in value in milliseconds for the acquired token * @ignore */ - AuthenticationContext.prototype._expiresIn = function (expires) { + AuthenticationContext.prototype._expiresIn = function (expires, state) { // if AAD did not send "expires_in" property, use default expiration of 3599 seconds, for some reason AAD sends 3599 as "expires_in" value instead of 3600 if (!expires) expires = 3599; - return this._now() + parseInt(expires, 10); + var expireBaseFromState = this._getExpireBaseTimeFromState(state) + if (expireBaseFromState === 0) { + return this._now() + parseInt(expires, 10); + } else { + return expireBaseFromState + parseInt(expires, 10); + } }; /** diff --git a/tests/unit/spec/AdalSpec.js b/tests/unit/spec/AdalSpec.js index a7dd11c3..c52c0f2a 100644 --- a/tests/unit/spec/AdalSpec.js +++ b/tests/unit/spec/AdalSpec.js @@ -256,7 +256,7 @@ describe('Adal', function () { }, 'iframe src not updated', 2000); runs(function () { - expect(mockFrames['adalRenewFrame' + RESOURCE1].src).toBe(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333%7Ctoken.resource1' + expect(mockFrames['adalRenewFrame' + RESOURCE1].src).toBe(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333%7Ctoken.resource1%7C1000' + '&client-request-id=33333333-3333-4333-b333-333333333333' + adal._addLibMetadata() + '&prompt=none&login_hint=test%40testuser.com&domain_hint=testuser.com'); }); @@ -291,7 +291,7 @@ describe('Adal', function () { }, 'iframe src not updated', 2000); runs(function () { - expect(mockFrames['adalRenewFrame' + RESOURCE1].src).toBe(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333%7Ctoken.resource1' + expect(mockFrames['adalRenewFrame' + RESOURCE1].src).toBe(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333%7Ctoken.resource1%7C1000' + '&client-request-id=33333333-3333-4333-b333-333333333333' + adal._addLibMetadata() + '&prompt=none&login_hint=test%40testuser.com&domain_hint=testuser.com'); }); @@ -766,13 +766,13 @@ describe('Adal', function () { adal._user = { profile: { 'upn': 'test@testuser.com' }, userName: 'test@domain.com' }; spyOn(adal, '_loadFrameTimeout'); adal.acquireToken(RESOURCE1, callback); - expect(adal._loadFrameTimeout).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333%7Ctoken.resource1' + expect(adal._loadFrameTimeout).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333%7Ctoken.resource1%7C1000' + '&client-request-id=33333333-3333-4333-b333-333333333333' + adal._addLibMetadata() + '&prompt=none&login_hint=test%40testuser.com&domain_hint=testuser.com', 'adalRenewFrametoken.resource1', 'token.resource1'); adal._activeRenewals = {}; adal._user = { profile: { 'sub': 'test@testuser.com' }, userName: 'test@domain.com' }; adal.acquireToken(RESOURCE1, callback); - expect(adal._loadFrameTimeout).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333%7Ctoken.resource1' + expect(adal._loadFrameTimeout).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333%7Ctoken.resource1%7C1000' + '&client-request-id=33333333-3333-4333-b333-333333333333' + adal._addLibMetadata() + '&prompt=none', 'adalRenewFrametoken.resource1', 'token.resource1'); }); @@ -790,7 +790,7 @@ describe('Adal', function () { }; spyOn(adal, '_loadFrameTimeout'); adal.acquireToken(RESOURCE1, callback); - expect(adal._loadFrameTimeout).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=11111111-1111-4111-9111-111111111111%7Ctoken.resource1' + expect(adal._loadFrameTimeout).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=11111111-1111-4111-9111-111111111111%7Ctoken.resource1%7C1000' + '&client-request-id=11111111-1111-4111-9111-111111111111' + adal._addLibMetadata() + '&prompt=none&login_hint=test%40testuser.com&domain_hint=testuser.com', 'adalRenewFrametoken.resource1', 'token.resource1'); mathMock.random = function () { @@ -799,7 +799,7 @@ describe('Adal', function () { adal._activeRenewals = {}; adal._user = { profile: { 'sub': 'test@testuser.com' }, userName: 'test@domain.com' }; adal.acquireToken(RESOURCE1, callback); - expect(adal._loadFrameTimeout).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=44444444-4444-4444-8444-444444444444%7Ctoken.resource1' + expect(adal._loadFrameTimeout).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=44444444-4444-4444-8444-444444444444%7Ctoken.resource1%7C1000' + '&client-request-id=44444444-4444-4444-8444-444444444444' + adal._addLibMetadata() + '&prompt=none', 'adalRenewFrametoken.resource1', 'token.resource1'); }); @@ -1019,6 +1019,19 @@ describe('Adal', function () { expect(storageFake.getItem(adal.CONSTANTS.STORAGE.EXPIRATION_KEY + 'loginResource1')).toBe(mathMock.round(1) + 3599); }); + it('tests specified expiration base time value for expires_in', function () { + var expirationBaseTime = 2000; + var requestInfo = { + valid: true, + parameters: { 'access_token': 'token123', 'state': '123' }, + stateMatch: true, + stateResponse: '123|loginResource1|' + expirationBaseTime, + requestType: adal.REQUEST_TYPE.RENEW_TOKEN + }; + adal.saveTokenFromHash(requestInfo); + expect(storageFake.getItem(adal.CONSTANTS.STORAGE.EXPIRATION_KEY + 'loginResource1')).toBe(expirationBaseTime + 3599); + }); + it('tests default value of redirect uri', function () { global.window = { location: { From 1f1acf7f02a4df06d83f659ddbb4ec4e66d2cc07 Mon Sep 17 00:00:00 2001 From: Gang Peng Date: Thu, 27 Feb 2020 16:30:17 -0800 Subject: [PATCH 36/36] Update the default value returned from _getExpireBaseTimeFromState() to be current local time, which simplifies logic inside _expiresIn function --- lib/adal.js | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/lib/adal.js b/lib/adal.js index da53d544..2cf77f59 100644 --- a/lib/adal.js +++ b/lib/adal.js @@ -1153,29 +1153,28 @@ var AuthenticationContext = (function () { */ AuthenticationContext.prototype._getResourceFromState = function (state) { if (state) { - var splittedInfo = state.split('|'); + var splitInfo = state.split('|'); - if (splittedInfo.length > 1) { - return splittedInfo[1]; + if (splitInfo.length > 1) { + return splitInfo[1]; } } - return ''; }; /** - * Extracts token expiration base time value from state. + * Extracts token expiration base time value from state, return current local time if state doesn't contain such info. * @ignore */ AuthenticationContext.prototype._getExpireBaseTimeFromState = function (state) { if (state) { - var splittedInfo = state.split('|'); + var splitInfo = state.split('|'); - if (splittedInfo.length > 2) { - return parseInt(splittedInfo[2], 10); + if (splitInfo.length > 2) { + return parseInt(splitInfo[2], 10); } } - return 0; + return this._now(); }; /** @@ -1673,12 +1672,7 @@ var AuthenticationContext = (function () { AuthenticationContext.prototype._expiresIn = function (expires, state) { // if AAD did not send "expires_in" property, use default expiration of 3599 seconds, for some reason AAD sends 3599 as "expires_in" value instead of 3600 if (!expires) expires = 3599; - var expireBaseFromState = this._getExpireBaseTimeFromState(state) - if (expireBaseFromState === 0) { - return this._now() + parseInt(expires, 10); - } else { - return expireBaseFromState + parseInt(expires, 10); - } + return this._getExpireBaseTimeFromState(state) + parseInt(expires, 10); }; /**