Socket
Socket
Sign inDemoInstall

adal-angular

Package Overview
Dependencies
0
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.10 to 1.0.11

instrumentedAdal.js

4

bower.json
{
"name": "adal-angular",
"version": "1.0.10",
"version": "1.0.11",
"homepage": "https://github.com/AzureAD/azure-activedirectory-library-for-js",

@@ -40,3 +40,3 @@ "authors": [

"angular-resource": "~1.2.26",
"angular-mocks": "~1.2.16",
"angular-mocks": "~1.2.26",
"jasmine": "2.0.0",

@@ -43,0 +43,0 @@ "angular-route": "~1.2.26"

@@ -0,1 +1,9 @@

Version 1.0.11
==========================
* Adding support for using a special html for iFrames. This prevents app reloading in the iframe. Please see this: https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/FAQs#q1-my-app-is-re-loading-every-time-adal-renews-a-token
* Fixing multiple root causes for infinte loops at the time of login or token renewal.
* Fixing url paramters getting dropped after login.
* Adding timeout to token renewal requests. Thanks @dmxfee for the Pull Request.
* Use module pattern in adal.js
Version 1.0.10

@@ -2,0 +10,0 @@ ==========================

@@ -1,2 +0,2 @@

/*! adal-angular v1.0.10 2016-05-09 */
"use strict";"undefined"!=typeof module&&module.exports&&(module.exports.inject=function(a){return new AuthenticationContext(a)}),function(){if(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");var e=window.location.hash,f=window.location.href;e&&(f=f.replace(e,"")),b.redirectUri=b.redirectUri||f,b.postLogoutRedirectUri=b.postLogoutRedirectUri||f,d&&d.interceptors&&d.interceptors.push("ProtectedResourceInterceptor"),a=new AuthenticationContext(b),c(a.config.loginResource)},this.$get=["$rootScope","$window","$q","$location","$timeout",function(d,e,f,g,h){function i(a,b){return b.requireADLogin?a.requireADLogin!==!1:!!a.requireADLogin}function j(b){if(a.config&&a.config.anonymousEndpoints)for(var c=0;c<a.config.anonymousEndpoints.length;c++)if(b.indexOf(a.config.anonymousEndpoints[c])>-1)return!0;return!1}var k=function(){var f=e.location.hash;if(a.isCallback(f)){var i=a.getRequestInfo(f);if(a.saveTokenFromHash(i),g.$$html5?e.location=e.location.origin+e.location.pathname:e.location.hash="",i.requestType!==a.REQUEST_TYPE.LOGIN&&(a.callback=e.parent.AuthenticationContext().callback,i.requestType===a.REQUEST_TYPE.RENEW_TOKEN&&(a.callback=e.parent.callBackMappedToRenewStates[i.stateResponse])),i.stateMatch)if("function"==typeof a.callback){if(i.requestType===a.REQUEST_TYPE.RENEW_TOKEN){if(i.parameters.access_token)return void a.callback(a._getItem(a.CONSTANTS.STORAGE.ERROR_DESCRIPTION),i.parameters.access_token);if(i.parameters.id_token)return void a.callback(a._getItem(a.CONSTANTS.STORAGE.ERROR_DESCRIPTION),i.parameters.id_token);if(i.parameters.error)return a.callback(a._getItem(a.CONSTANTS.STORAGE.ERROR_DESCRIPTION),null),void(a._renewFailed=!0)}}else c(a.config.loginResource),b.userName?(h(function(){c(a.config.loginResource),d.userInfo=b;var e=a._getItem(a.CONSTANTS.STORAGE.START_PAGE);if(e){var f=a._getItem(a.CONSTANTS.STORAGE.START_PAGE_PARAMS);if(f){var h=JSON.parse(f);g.url(e).search(h)}else g.url(e)}},1),d.$broadcast("adal:loginSuccess")):d.$broadcast("adal:loginFailure",a._getItem(a.CONSTANTS.STORAGE.ERROR_DESCRIPTION));else d.$broadcast("adal:stateMismatch",a._getItem(a.CONSTANTS.STORAGE.ERROR_DESCRIPTION))}else c(a.config.loginResource),b.isAuthenticated||!b.userName||a._renewActive||a._renewFailed||(a._renewActive=!0,a.acquireToken(a.config.loginResource,function(c,e){a._renewActive=!1,c?d.$broadcast("adal:loginFailure","auto renew failure"):e&&(b.isAuthenticated=!0)}));h(function(){c(a.config.loginResource),d.userInfo=b},1)},l=function(){a.info("Login event for:"+g.$$url),a.config&&a.config.localLoginUrl?g.path(a.config.localLoginUrl):(a._saveItem(a.CONSTANTS.STORAGE.START_PAGE,g.$$url),a.info("Start login at:"+window.location.href),d.$broadcast("adal:loginRedirect"),a.login())},m=function(c,d){d&&d.$$route&&(i(d.$$route,a.config)?b.isAuthenticated||a._renewActive||(a.info("Route change event for:"+g.$$url),l()):d.$$route.templateUrl&&!j(d.$$route.templateUrl)&&a.config.anonymousEndpoints.push(d.$$route.templateUrl))},n=function(c,d,e,f,h){d&&(i(d,a.config)?b.isAuthenticated||a._renewActive||(g.$$url=d.url,a._saveItem(a.CONSTANTS.STORAGE.START_PAGE_PARAMS,JSON.stringify(e)),a.info("State change event for:"+g.$$url),l()):d.templateUrl&&!j(d.templateUrl)&&a.config.anonymousEndpoints.push(d.templateUrl))};return d.$on("$routeChangeStart",m),d.$on("$stateChangeStart",n),d.$on("$locationChangeStart",k),c(a.config.loginResource),d.userInfo=b,{config:a.config,login:function(){a.login()},loginInProgress:function(){return a.loginInProgress()},logOut:function(){a.logOut()},getCachedToken:function(b){return a.getCachedToken(b)},userInfo:b,acquireToken:function(b){var c=f.defer();return a._renewActive=!0,a.acquireToken(b,function(d,e){a._renewActive=!1,d?(a.error("Error when acquiring token for resource: "+b,d),c.reject(d)):c.resolve(e)}),c.promise},getUser:function(){var b=f.defer();return a.getUser(function(c,d){c?(a.error("Error when getting user",c),b.reject(c)):b.resolve(d)}),b.promise},getResourceForEndpoint:function(b){return a.getResourceForEndpoint(b)},clearCache:function(){a.clearCache()},clearCacheForResource:function(b){a.clearCacheForResource(b)},info:function(b){a.info(b)},verbose:function(b){a.verbose(b)}}}]}),a.factory("ProtectedResourceInterceptor",["adalAuthenticationService","$q","$rootScope",function(a,b,c){return{request:function(c){if(c){c.headers=c.headers||{};var d=a.getResourceForEndpoint(c.url);if(a.verbose("Url: "+c.url+" maps to resource: "+d),null===d)return c;var e=a.getCachedToken(d);if(e)return a.info("Token is avaliable for this url "+c.url),c.headers.Authorization="Bearer "+e,c;if(a.loginInProgress())return a.info("login already start."),b.reject("login in progress, cancelling the request");var f=b.defer();return a.acquireToken(d).then(function(b){a.verbose("Token is avaliable"),c.headers.Authorization="Bearer "+b,f.resolve(c)},function(a){f.reject(a)}),f.promise}},responseError:function(d){if(a.info("Getting error in the response"),d){if(401===d.status){var e=a.getResourceForEndpoint(d.config.url);a.clearCacheForResource(e),c.$broadcast("adal:notAuthorized",d,e)}else c.$broadcast("adal:errorResponse",d);return b.reject(d)}}}}])}else console.error("Angular.JS is not included")}();
/*! adal-angular v1.0.11 2016-07-19 */
!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");var e=window.location.hash,f=window.location.href;e&&(f=f.replace(e,"")),b.redirectUri=b.redirectUri||f,b.postLogoutRedirectUri=b.postLogoutRedirectUri||f,d&&d.interceptors&&d.interceptors.push("ProtectedResourceInterceptor"),a=new AuthenticationContext(b),c(a.config.loginResource)},this.$get=["$rootScope","$window","$q","$location","$timeout",function(d,e,f,g,h){function i(a,b){return b.requireADLogin?a.requireADLogin!==!1:!!a.requireADLogin}function j(b){if(a.config&&a.config.anonymousEndpoints)for(var c=0;c<a.config.anonymousEndpoints.length;c++)if(b.indexOf(a.config.anonymousEndpoints[c])>-1)return!0;return!1}var k=function(f,i,j){a.verbose("Location change event from "+j+" to "+i);var k=e.location.hash;if(a.isCallback(k)){a.verbose("Processing the hash: "+k);var l=a.getRequestInfo(k);if(a.saveTokenFromHash(l),l.requestType!==a.REQUEST_TYPE.LOGIN&&(a.callback=e.parent.AuthenticationContext().callback,l.requestType===a.REQUEST_TYPE.RENEW_TOKEN&&(a.callback=e.parent.callBackMappedToRenewStates[l.stateResponse])),l.stateMatch)if("function"==typeof a.callback){if(f.preventDefault(),l.requestType===a.REQUEST_TYPE.RENEW_TOKEN){if(l.parameters.access_token)return void a.callback(a._getItem(a.CONSTANTS.STORAGE.ERROR_DESCRIPTION),l.parameters.access_token);if(l.parameters.id_token)return void a.callback(a._getItem(a.CONSTANTS.STORAGE.ERROR_DESCRIPTION),l.parameters.id_token);if(l.parameters.error)return void a.callback(a._getItem(a.CONSTANTS.STORAGE.ERROR_DESCRIPTION),null)}}else{c(a.config.loginResource),b.userName?(h(function(){c(a.config.loginResource),d.userInfo=b},1),d.$broadcast("adal:loginSuccess")):d.$broadcast("adal:loginFailure",a._getItem(a.CONSTANTS.STORAGE.ERROR_DESCRIPTION));var m=a._getItem(a.CONSTANTS.STORAGE.LOGIN_REQUEST);m&&(a.verbose("Redirecting to start page: "+m),f.preventDefault(),!g.$$html5&&m.indexOf("#")>-1&&g.url(m.substring(m.indexOf("#")+1)),e.location=m)}else d.$broadcast("adal:stateMismatch",a._getItem(a.CONSTANTS.STORAGE.ERROR_DESCRIPTION))}else c(a.config.loginResource),b.isAuthenticated||!b.userName||a._renewActive||(a._renewActive=!0,a.acquireToken(a.config.loginResource,function(c,e){a._renewActive=!1,c?d.$broadcast("adal:loginFailure","auto renew failure"):e&&(b.isAuthenticated=!0)}));h(function(){c(a.config.loginResource),d.userInfo=b},1)},l=function(){a.info("Login event for:"+g.$$url),a.config&&a.config.localLoginUrl?g.path(a.config.localLoginUrl):(a.info("Start login at:"+window.location.href),d.$broadcast("adal:loginRedirect"),a.login())},m=function(c,d){d&&d.$$route&&(i(d.$$route,a.config)?b.isAuthenticated||a._renewActive||a.loginInProgress()||(a.info("Route change event for:"+g.$$url),l()):d.$$route.templateUrl&&!j(d.$$route.templateUrl)&&a.config.anonymousEndpoints.push(d.$$route.templateUrl))},n=function(c,d,e,f,h){d&&(i(d,a.config)?b.isAuthenticated||a._renewActive||a.loginInProgress()||(a.info("State change event for:"+g.$$url),l()):d.templateUrl&&!j(d.templateUrl)&&a.config.anonymousEndpoints.push(d.templateUrl))},o=function(b,c,d,e,f,g){a.verbose("State change error occured. Error: "+g),g&&g.data&&(a.info("Setting defaultPrevented to true if state change error occured because adal rejected a request. Error: "+g.data),b.preventDefault())};return d.$on("$routeChangeStart",m),d.$on("$stateChangeStart",n),d.$on("$locationChangeStart",k),d.$on("$stateChangeError",o),c(a.config.loginResource),d.userInfo=b,{config:a.config,login:function(){l()},loginInProgress:function(){return a.loginInProgress()},logOut:function(){a.logOut()},getCachedToken:function(b){return a.getCachedToken(b)},userInfo:b,acquireToken:function(b){var c=f.defer();return a._renewActive=!0,a.acquireToken(b,function(d,e){a._renewActive=!1,d?(a.error("Error when acquiring token for resource: "+b,d),c.reject(d)):c.resolve(e)}),c.promise},getUser:function(){var b=f.defer();return a.getUser(function(c,d){c?(a.error("Error when getting user",c),b.reject(c)):b.resolve(d)}),b.promise},getResourceForEndpoint:function(b){return a.getResourceForEndpoint(b)},clearCache:function(){a.clearCache()},clearCacheForResource:function(b){a.clearCacheForResource(b)},info:function(b){a.info(b)},verbose:function(b){a.verbose(b)}}}]}),a.factory("ProtectedResourceInterceptor",["adalAuthenticationService","$q","$rootScope",function(a,b,c){return{request:function(c){if(c){c.headers=c.headers||{};var d=a.getResourceForEndpoint(c.url);if(a.verbose("Url: "+c.url+" maps to resource: "+d),null===d)return c;var e=a.getCachedToken(d);if(e)return a.info("Token is available for this url "+c.url),c.headers.Authorization="Bearer "+e,c;if(a.loginInProgress())return a.info("login is in progress."),c.data="login in progress, cancelling the request for "+c.url,b.reject(c);var f=b.defer();return a.acquireToken(d).then(function(b){a.verbose("Token is available"),c.headers.Authorization="Bearer "+b,f.resolve(c)},function(a){c.data=a,f.reject(c)}),f.promise}},responseError:function(d){if(a.info("Getting error in the response."),d){if(401===d.status){var e=a.getResourceForEndpoint(d.config.url);a.clearCacheForResource(e),c.$broadcast("adal:notAuthorized",d,e)}else c.$broadcast("adal:errorResponse",d);return b.reject(d)}}}}])}else console.error("Angular.JS is not included")}();

@@ -1,2 +0,2 @@

/*! adal-angular v1.0.10 2016-05-09 */
"use strict";var Logging={level:0,log:function(){}},AuthenticationContext;"undefined"!=typeof module&&module.exports&&(module.exports.inject=function(a){return new AuthenticationContext(a)}),AuthenticationContext=function(a){if(this.REQUEST_TYPE={LOGIN:"LOGIN",RENEW_TOKEN:"RENEW_TOKEN",UNKNOWN:"UNKNOWN"},this.CONSTANTS={ACCESS_TOKEN:"access_token",EXPIRES_IN:"expires_in",ID_TOKEN:"id_token",ERROR_DESCRIPTION:"error_description",SESSION_STATE:"session_state",STORAGE:{TOKEN_KEYS:"adal.token.keys",ACCESS_TOKEN_KEY:"adal.access.token.key",EXPIRATION_KEY:"adal.expiration.key",START_PAGE:"adal.start.page",START_PAGE_PARAMS:"adal.start.page.params",STATE_LOGIN:"adal.state.login",STATE_RENEW:"adal.state.renew",STATE_RENEW_RESOURCE:"adal.state.renew.resource",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"},RESOURCE_DELIMETER:"|",ERR_MESSAGES:{NO_TOKEN:"User is not authorized"},LOGGING_LEVEL:{ERROR:0,WARN:1,INFO:2,VERBOSE:3},LEVEL_STRING_MAP:{0:"ERROR:",1:"WARNING:",2:"INFO:",3:"VERBOSE:"}},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._user=null,this._activeRenewals={},this._loginInProgress=!1,this._renewStates=[],window.callBackMappedToRenewStates={},window.callBacksMappedToRenewStates={},a.displayCall&&"function"!=typeof a.displayCall)throw new Error("displayCall is not a function");if(!a.clientId)throw new Error("clientId is required");a.correlationId||(a.correlationId=this._guid()),this.config=this._cloneConfig(a),this.config.loginResource||(this.config.loginResource=this.config.clientId),this.config.redirectUri||(this.config.redirectUri=window.location.href)},AuthenticationContext.prototype.login=function(){var a=this._guid();this.config.state=a,this._idTokenNonce=this._guid(),this.verbose("Expected state: "+a+" startPage:"+window.location),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST,window.location),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN,a),this._saveItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN,this._idTokenNonce),this._saveItem(this.CONSTANTS.STORAGE.ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,"");var b=this._getNavigateUrl("id_token",null)+"&nonce="+encodeURIComponent(this._idTokenNonce);this.frameCallInProgress=!1,this._loginInProgress=!0,this.config.displayCall?this.config.displayCall(b):this.promptUser(b)},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||120;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,window.callBacksMappedToRenewStates[a]||(window.callBacksMappedToRenewStates[a]=[]);var d=this;window.callBacksMappedToRenewStates[a].push(c),window.callBackMappedToRenewStates[a]||(window.callBackMappedToRenewStates[a]=function(c,e){for(var f=0;f<window.callBacksMappedToRenewStates[a].length;++f)window.callBacksMappedToRenewStates[a][f](c,e);d._activeRenewals[b]=null,window.callBacksMappedToRenewStates[a]=null,window.callBackMappedToRenewStates[a]=null})},AuthenticationContext.prototype._renewToken=function(a,b){this.info("renewToken is called for resource:"+a);var c=this._addAdalFrame("adalRenewFrame"+a),d=this._guid()+"|"+a;this._idTokenNonce=this._guid(),this.config.state=d,this._renewStates.push(d),this.verbose("Renew token Expected state: "+d);var e=this._getNavigateUrl("token",a)+"&prompt=none&login_hint="+encodeURIComponent(this._user.userName);this._urlContainsQueryStringParameter("domain_hint",e)||(e+="&domain_hint="+encodeURIComponent(this._getDomainHint())),e+="&nonce="+encodeURIComponent(this._idTokenNonce),this.callback=b,this.registerCallback(d,a,b),this.idTokenNonce=null,this.verbose("Navigate to:"+e),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST,""),c.src="about:blank",this._loadFrame(e,"adalRenewFrame"+a)},AuthenticationContext.prototype._renewIdToken=function(a){this.info("renewIdToken is called");var b=this._addAdalFrame("adalIdTokenFrame"),c=this._guid()+"|"+this.config.clientId;this._idTokenNonce=this._guid(),this._saveItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN,this._idTokenNonce),this.config.state=c,this._renewStates.push(c),this.verbose("Renew Idtoken Expected state: "+c);var d=this._getNavigateUrl("id_token",null)+"&prompt=none&login_hint="+encodeURIComponent(this._user.userName);this._urlContainsQueryStringParameter("domain_hint",d)||(d+="&domain_hint="+encodeURIComponent(this._getDomainHint())),d+="&nonce="+encodeURIComponent(this._idTokenNonce),this.registerCallback(c,this.config.clientId,a),this.idTokenNonce=null,this.verbose("Navigate to:"+d),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST,""),b.src="about:blank",this._loadFrame(d,"adalIdTokenFrame")},AuthenticationContext.prototype._urlContainsQueryStringParameter=function(a,b){var c=new RegExp("[\\?&]"+a+"=");return c.test(b)},AuthenticationContext.prototype._loadFrame=function(a,b){var c=this;c.info("LoadFrame: "+b);var d=b;setTimeout(function(){var b=c._addAdalFrame(d);""!==b.src&&"about:blank"!==b.src||(b.src=a,c._loadFrame(a,d))},500)},AuthenticationContext.prototype.acquireToken=function(a,b){if(this._isEmpty(a))return this.warn("resource is required"),void b("resource is required",null);var c=this.getCachedToken(a);return c?(this.info("Token is already in cache for resource:"+a),void b(null,c)):this._user?void(this._activeRenewals[a]?this.registerCallback(this._activeRenewals[a],a,b):a===this.config.clientId?(this.verbose("renewing idtoken"),this._renewIdToken(b)):this._renewToken(a,b)):(this.warn("User login is required"),void b("User login is required",null))},AuthenticationContext.prototype.promptUser=function(a){a?(this.info("Navigate to:"+a),window.location.replace(a)):this.info("Navigate url is empty")},AuthenticationContext.prototype.clearCache=function(){this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY,""),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY,0),this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE,""),this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN,""),this._renewStates=[],this._saveItem(this.CONSTANTS.STORAGE.START_PAGE,""),this._saveItem(this.CONSTANTS.STORAGE.START_PAGE_PARAMS,""),this._saveItem(this.CONSTANTS.STORAGE.USERNAME,""),this._saveItem(this.CONSTANTS.STORAGE.IDTOKEN,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,"");var a=this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS);if(!this._isEmpty(a)){a=a.split(this.CONSTANTS.RESOURCE_DELIMETER);for(var b=0;b<a.length;b++)this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+a[b],""),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+a[b],0)}this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS,"")},AuthenticationContext.prototype.clearCacheForResource=function(a){this._saveItem(this.CONSTANTS.STORAGE.STATE_RENEW,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,""),this._hasResource(a)&&(this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+a,""),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+a,0))},AuthenticationContext.prototype.logOut=function(){this.clearCache();var a="common",b="";this._user=null,this.config.tenant&&(a=this.config.tenant),this.config.instance&&(this.instance=this.config.instance),this.config.postLogoutRedirectUri&&(b="post_logout_redirect_uri="+encodeURIComponent(this.config.postLogoutRedirectUri));var c=this.instance+a+"/oauth2/logout?"+b;this.info("Logout navigate to: "+c),this.promptUser(c)},AuthenticationContext.prototype._isEmpty=function(a){return"undefined"==typeof a||!a||0===a.length},AuthenticationContext.prototype.getUser=function(a){if("function"!=typeof a)throw new Error("callback is not a function");if(this.callback=a,this._user)return void this.callback(null,this._user);var b=this._getItem(this.CONSTANTS.STORAGE.IDTOKEN);this._isEmpty(b)?(this.warn("User information is not available"),this.callback("User information is not available")):(this.info("User exists in cache: "),this._user=this._createUser(b),this.callback(null,this._user))},AuthenticationContext.prototype._getDomainHint=function(){if(this._user&&this._user.userName&&this._user.userName.indexOf("@")>-1){var a=this._user.userName.split("@");return a[a.length-1]}return""},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,d===this._getItem(this.CONSTANTS.STORAGE.STATE_LOGIN))return c.requestType=this.REQUEST_TYPE.LOGIN,c.stateMatch=!0,c;if(!c.stateMatch&&window.parent&&window.parent.AuthenticationContext())for(var e=window.parent.AuthenticationContext()._renewStates,f=0;f<e.length;f++)if(e[f]===c.stateResponse){c.requestType=this.REQUEST_TYPE.RENEW_TOKEN,c.stateMatch=!0;break}}return c},AuthenticationContext.prototype._getResourceFromState=function(a){if(a){var b=a.indexOf("|");if(b>-1&&b+1<a.length)return a.substring(b+1)}return""},AuthenticationContext.prototype.saveTokenFromHash=function(a){if(this.info("State status:"+a.stateMatch+"; Request type:"+a.requestType),this._saveItem(this.CONSTANTS.STORAGE.ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,""),a.parameters.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION))this.info("Error :"+a.parameters.error+"; Error description:"+a.parameters[this.CONSTANTS.ERROR_DESCRIPTION]),this._saveItem(this.CONSTANTS.STORAGE.ERROR,a.parameters.error),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,a.parameters[this.CONSTANTS.ERROR_DESCRIPTION]),a.requestType===this.REQUEST_TYPE.LOGIN&&(this._loginInProgress=!1,this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR,a.parameters.errorDescription));else if(a.stateMatch){this.info("State is right"),a.parameters.hasOwnProperty(this.CONSTANTS.SESSION_STATE)&&this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE,a.parameters[this.CONSTANTS.SESSION_STATE]);var b,c;a.parameters.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN)&&(this.info("Fragment has access token"),c=this._getResourceFromState(a.stateResponse),this._hasResource(c)||(b=this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS)||"",this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS,b+c+this.CONSTANTS.RESOURCE_DELIMETER)),this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+c,a.parameters[this.CONSTANTS.ACCESS_TOKEN]),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+c,this._expiresIn(a.parameters[this.CONSTANTS.EXPIRES_IN]))),a.parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)&&(this.info("Fragment has id token"),this._loginInProgress=!1,this._user=this._createUser(a.parameters[this.CONSTANTS.ID_TOKEN]),this._user&&this._user.profile&&(this._user.profile.nonce!==this._getItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN)?(this._user=null,this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR,"Nonce is not same as "+this._idTokenNonce)):(this._saveItem(this.CONSTANTS.STORAGE.IDTOKEN,a.parameters[this.CONSTANTS.ID_TOKEN]),c=this.config.loginResource?this.config.loginResource:this.config.clientId,this._hasResource(c)||(b=this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS)||"",this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS,b+c+this.CONSTANTS.RESOURCE_DELIMETER)),this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+c,a.parameters[this.CONSTANTS.ID_TOKEN]),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+c,this._user.profile.exp))))}else this._saveItem(this.CONSTANTS.STORAGE.ERROR,"Invalid_state"),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,"Invalid_state. state: "+a.stateResponse)},AuthenticationContext.prototype.getResourceForEndpoint=function(a){if(this.config&&this.config.endpoints)for(var b in this.config.endpoints)if(a.indexOf(b)>-1)return this.config.endpoints[b];if(!(a.indexOf("http://")>-1||a.indexOf("https://")>-1)){if(this.config&&this.config.anonymousEndpoints)for(var c=0;c<this.config.anonymousEndpoints.length;c++)if(a.indexOf(this.config.anonymousEndpoints[c])>-1)return null;return this.config.loginResource}return this._getHostFromUri(a)===this._getHostFromUri(this.config.redirectUri)?this.config.loginResource:null},AuthenticationContext.prototype._getHostFromUri=function(a){var b=String(a).replace(/^(https?:)\/\//,"");return b=b.split("/")[0]},AuthenticationContext.prototype.handleWindowCallback=function(){var a=window.location.hash;if(this.isCallback(a)){var b=this.getRequestInfo(a);this.info("Returned from redirect url"),this.saveTokenFromHash(b);var c=null;if(b.requestType===this.REQUEST_TYPE.RENEW_TOKEN&&window.parent?(this.verbose("Window is in iframe"),c=window.parent.callBackMappedToRenewStates[b.stateResponse],window.src=""):window&&window.oauth2Callback&&(this.verbose("Window is redirecting"),c=this.callback),window.location.hash="",window.location=this._getItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST),b.requestType===this.REQUEST_TYPE.RENEW_TOKEN)return void c(this._getItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION),b.parameters[this.CONSTANTS.ACCESS_TOKEN]||b.parameters[this.CONSTANTS.ID_TOKEN])}},AuthenticationContext.prototype._getNavigateUrl=function(a,b){var c="common";this.config.tenant&&(c=this.config.tenant),this.config.instance&&(this.instance=this.config.instance);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(e){this.error("The returned id_token could not be decoded",e)}return null},AuthenticationContext.prototype._extractUserName=function(a){try{var b=this._extractIdToken(a);if(b){if(b.hasOwnProperty("upn"))return b.upn;if(b.hasOwnProperty("email"))return b.email}}catch(c){this.error("The returned id_token could not be decoded",c)}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;c>m;m+=4){if(d=b.indexOf(a.charAt(m)),e=b.indexOf(a.charAt(m+1)),f=b.indexOf(a.charAt(m+2)),g=b.indexOf(a.charAt(m+3)),m+2===c-1){h=d<<18|e<<12|f<<6,i=h>>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);if(!c||c.length<4)return this.warn("The returned id_token is not parseable."),null;var d={header:c[1],JWSPayload:c[2],JWSSig:c[3]};return d},AuthenticationContext.prototype._convertUrlSafeToRegularBase64EncodedString=function(a){return a.replace("-","+").replace("_","/")},AuthenticationContext.prototype._serialize=function(a,b,c){var d=[];return 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),b.correlationId&&d.push("client-request-id="+encodeURIComponent(b.correlationId))),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._guid=function(){for(var a="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx",b="0123456789abcdef",c=0,d="",e=0;36>e;e++)"-"!==a[e]&&"4"!==a[e]&&(c=16*Math.random()|0),"x"===a[e]?d+=b[c]:"y"===a[e]?(c&=3,c|=8,d+=b[c]):d+=a[e];return d},AuthenticationContext.prototype._expiresIn=function(a){return this._now()+parseInt(a,10)},AuthenticationContext.prototype._now=function(){return Math.round((new Date).getTime()/1e3)},AuthenticationContext.prototype._addAdalFrame=function(a){if("undefined"!=typeof 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.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",'<iframe name="'+a+'" id="'+a+'" style="display:none"></iframe>');window.frames&&window.frames[a]&&(b=window.frames[a])}return b}},AuthenticationContext.prototype._saveItem=function(a,b){return this.config&&this.config.cacheLocation&&"localStorage"===this.config.cacheLocation?this._supportsLocalStorage()?(localStorage.setItem(a,b),!0):(this.info("Local storage is not supported"),!1):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"localStorage"in window&&window.localStorage}catch(a){return!1}},AuthenticationContext.prototype._supportsSessionStorage=function(){try{return"sessionStorage"in window&&window.sessionStorage}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){if(a<=Logging.level){var d=this.config.correlationId,e=(new Date).toUTCString(),f=e+":"+d+"-"+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._libVersion=function(){return"1.0.10"};
/*! adal-angular v1.0.11 2016-07-19 */
var AuthenticationContext=function(){"use strict";return AuthenticationContext=function(a){if(this.REQUEST_TYPE={LOGIN:"LOGIN",RENEW_TOKEN:"RENEW_TOKEN",UNKNOWN:"UNKNOWN"},this.CONSTANTS={ACCESS_TOKEN:"access_token",EXPIRES_IN:"expires_in",ID_TOKEN:"id_token",ERROR_DESCRIPTION:"error_description",SESSION_STATE:"session_state",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",STATE_RENEW_RESOURCE:"adal.state.renew.resource",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"},RESOURCE_DELIMETER:"|",ERR_MESSAGES:{NO_TOKEN:"User is not authorized"},LOADFRAME_TIMEOUT:"6000",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:"}},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._user=null,this._activeRenewals={},this._loginInProgress=!1,this._renewStates=[],window.callBackMappedToRenewStates={},window.callBacksMappedToRenewStates={},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),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),this.config.anonymousEndpoints||(this.config.anonymousEndpoints=[])},window.Logging={level:0,log:function(a){}},AuthenticationContext.prototype.login=function(){var a=this._guid();this.config.state=a,this._idTokenNonce=this._guid(),this.verbose("Expected state: "+a+" startPage:"+window.location),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST,window.location),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN,a),this._saveItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN,this._idTokenNonce),this._saveItem(this.CONSTANTS.STORAGE.ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,"");var b=this._getNavigateUrl("id_token",null)+"&nonce="+encodeURIComponent(this._idTokenNonce);this.frameCallInProgress=!1,this._loginInProgress=!0,this.config.displayCall?this.config.displayCall(b):this.promptUser(b)},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||120;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,window.callBacksMappedToRenewStates[a]||(window.callBacksMappedToRenewStates[a]=[]);var d=this;window.callBacksMappedToRenewStates[a].push(c),window.callBackMappedToRenewStates[a]||(window.callBackMappedToRenewStates[a]=function(c,e){for(var f=0;f<window.callBacksMappedToRenewStates[a].length;++f)window.callBacksMappedToRenewStates[a][f](c,e);d._activeRenewals[b]=null,window.callBacksMappedToRenewStates[a]=null,window.callBackMappedToRenewStates[a]=null})},AuthenticationContext.prototype._renewToken=function(a,b){this.info("renewToken is called for resource:"+a);var c=this._addAdalFrame("adalRenewFrame"+a),d=this._guid()+"|"+a;this.config.state=d,this._renewStates.push(d),this.verbose("Renew token Expected state: "+d);var e=this._getNavigateUrl("token",a)+"&prompt=none";e=this._addHintParameters(e),this.callback=b,this.registerCallback(d,a,b),this.verbose("Navigate to:"+e),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST,""),c.src="about:blank",this._loadFrameTimeout(e,"adalRenewFrame"+a,a)},AuthenticationContext.prototype._renewIdToken=function(a){this.info("renewIdToken is called");var b=this._addAdalFrame("adalIdTokenFrame"),c=this._guid()+"|"+this.config.clientId;this._idTokenNonce=this._guid(),this._saveItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN,this._idTokenNonce),this.config.state=c,this._renewStates.push(c),this.verbose("Renew Idtoken Expected state: "+c);var d=this._getNavigateUrl("id_token",null)+"&prompt=none";d=this._addHintParameters(d),d+="&nonce="+encodeURIComponent(this._idTokenNonce),this.registerCallback(c,this.config.clientId,a),this.idTokenNonce=null,this.verbose("Navigate to:"+d),this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST,""),b.src="about:blank",this._loadFrameTimeout(d,"adalIdTokenFrame",this.config.clientId)},AuthenticationContext.prototype._urlContainsQueryStringParameter=function(a,b){var c=new RegExp("[\\?&]"+a+"=");return c.test(b)},AuthenticationContext.prototype._loadFrameTimeout=function(a,b,c){this.verbose("Set loading state to pending for: "+c),this._saveItem(this.CONSTANTS.STORAGE.RENEW_STATUS+c,this.CONSTANTS.TOKEN_RENEW_STATUS_IN_PROGRESS),this._loadFrame(a,b);var d=this;setTimeout(function(){if(d._getItem(d.CONSTANTS.STORAGE.RENEW_STATUS+c)===d.CONSTANTS.TOKEN_RENEW_STATUS_IN_PROGRESS){d.verbose("Loading frame has timed out after: "+d.CONSTANTS.LOADFRAME_TIMEOUT/1e3+" seconds for resource "+c);var a=d._activeRenewals[c];a&&window.callBackMappedToRenewStates[a]&&window.callBackMappedToRenewStates[a]("Token renewal operation failed due to timeout",null),d._saveItem(d.CONSTANTS.STORAGE.RENEW_STATUS+c,d.CONSTANTS.TOKEN_RENEW_STATUS_CANCELED)}},d.CONSTANTS.LOADFRAME_TIMEOUT)},AuthenticationContext.prototype._loadFrame=function(a,b){var c=this;c.info("LoadFrame: "+b);var d=b;setTimeout(function(){var b=c._addAdalFrame(d);""!==b.src&&"about:blank"!==b.src||(b.src=a,c._loadFrame(a,d))},500)},AuthenticationContext.prototype.acquireToken=function(a,b){if(this._isEmpty(a))return this.warn("resource is required"),void b("resource is required",null);var c=this.getCachedToken(a);return c?(this.info("Token is already in cache for resource:"+a),void b(null,c)):this._user?void(this._activeRenewals[a]?this.registerCallback(this._activeRenewals[a],a,b):a===this.config.clientId?(this.verbose("renewing idtoken"),this._renewIdToken(b)):this._renewToken(a,b)):(this.warn("User login is required"),void b("User login is required",null))},AuthenticationContext.prototype.promptUser=function(a){a?(this.info("Navigate to:"+a),window.location.replace(a)):this.info("Navigate url is empty")},AuthenticationContext.prototype.clearCache=function(){this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY,""),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY,0),this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE,""),this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN,""),this._renewStates=[],this._saveItem(this.CONSTANTS.STORAGE.USERNAME,""),this._saveItem(this.CONSTANTS.STORAGE.IDTOKEN,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,"");var a=this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS);if(!this._isEmpty(a)){a=a.split(this.CONSTANTS.RESOURCE_DELIMETER);for(var b=0;b<a.length;b++)this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+a[b],""),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+a[b],0)}this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS,"")},AuthenticationContext.prototype.clearCacheForResource=function(a){this._saveItem(this.CONSTANTS.STORAGE.STATE_RENEW,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,""),this._hasResource(a)&&(this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+a,""),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+a,0))},AuthenticationContext.prototype.logOut=function(){this.clearCache();var a="common",b="";this._user=null,this.config.tenant&&(a=this.config.tenant),this.config.postLogoutRedirectUri&&(b="post_logout_redirect_uri="+encodeURIComponent(this.config.postLogoutRedirectUri));var c=this.instance+a+"/oauth2/logout?"+b;this.info("Logout navigate to: "+c),this.promptUser(c)},AuthenticationContext.prototype._isEmpty=function(a){return"undefined"==typeof a||!a||0===a.length},AuthenticationContext.prototype.getUser=function(a){if("function"!=typeof a)throw new Error("callback is not a function");if(this.callback=a,this._user)return void this.callback(null,this._user);var b=this._getItem(this.CONSTANTS.STORAGE.IDTOKEN);this._isEmpty(b)?(this.warn("User information is not available"),this.callback("User information is not available")):(this.info("User exists in cache: "),this._user=this._createUser(b),this.callback(null,this._user))},AuthenticationContext.prototype._addHintParameters=function(a){if(this._user&&this._user.profile&&this._user.profile.hasOwnProperty("upn")&&(a+="&login_hint="+encodeURIComponent(this._user.profile.upn),!this._urlContainsQueryStringParameter("domain_hint",a)&&this._user.profile.upn.indexOf("@")>-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,d===this._getItem(this.CONSTANTS.STORAGE.STATE_LOGIN))return c.requestType=this.REQUEST_TYPE.LOGIN,c.stateMatch=!0,c;if(!c.stateMatch&&window.parent&&window.parent.AuthenticationContext())for(var e=window.parent.AuthenticationContext()._renewStates,f=0;f<e.length;f++)if(e[f]===c.stateResponse){c.requestType=this.REQUEST_TYPE.RENEW_TOKEN,c.stateMatch=!0;break}}return c},AuthenticationContext.prototype._getResourceFromState=function(a){if(a){var b=a.indexOf("|");if(b>-1&&b+1<a.length)return a.substring(b+1)}return""},AuthenticationContext.prototype.saveTokenFromHash=function(a){this.info("State status:"+a.stateMatch+"; Request type:"+a.requestType),this._saveItem(this.CONSTANTS.STORAGE.ERROR,""),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,"");var b=this._getResourceFromState(a.stateResponse);if(a.parameters.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION))this.info("Error :"+a.parameters.error+"; Error description:"+a.parameters[this.CONSTANTS.ERROR_DESCRIPTION]),this._saveItem(this.CONSTANTS.STORAGE.ERROR,a.parameters.error),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,a.parameters[this.CONSTANTS.ERROR_DESCRIPTION]),a.requestType===this.REQUEST_TYPE.LOGIN&&(this._loginInProgress=!1,this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR,a.parameters.error_description));else if(a.stateMatch){this.info("State is right"),a.parameters.hasOwnProperty(this.CONSTANTS.SESSION_STATE)&&this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE,a.parameters[this.CONSTANTS.SESSION_STATE]);var c;a.parameters.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN)&&(this.info("Fragment has access token"),this._hasResource(b)||(c=this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS)||"",this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS,c+b+this.CONSTANTS.RESOURCE_DELIMETER)),this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+b,a.parameters[this.CONSTANTS.ACCESS_TOKEN]),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+b,this._expiresIn(a.parameters[this.CONSTANTS.EXPIRES_IN]))),a.parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)&&(this.info("Fragment has id token"),this._loginInProgress=!1,this._user=this._createUser(a.parameters[this.CONSTANTS.ID_TOKEN]),this._user&&this._user.profile?this._user.profile.nonce!==this._getItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN)?(this._user=null,this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR,"Nonce is not same as "+this._idTokenNonce)):(this._saveItem(this.CONSTANTS.STORAGE.IDTOKEN,a.parameters[this.CONSTANTS.ID_TOKEN]),b=this.config.loginResource?this.config.loginResource:this.config.clientId,this._hasResource(b)||(c=this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS)||"",this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS,c+b+this.CONSTANTS.RESOURCE_DELIMETER)),this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY+b,a.parameters[this.CONSTANTS.ID_TOKEN]),this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY+b,this._user.profile.exp)):(this._saveItem(this.CONSTANTS.STORAGE.ERROR,"invalid id_token"),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,"Invalid id_token. id_token: "+a.parameters[this.CONSTANTS.ID_TOKEN])))}else this._saveItem(this.CONSTANTS.STORAGE.ERROR,"Invalid_state"),this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION,"Invalid_state. state: "+a.stateResponse);this._saveItem(this.CONSTANTS.STORAGE.RENEW_STATUS+b,this.CONSTANTS.TOKEN_RENEW_STATUS_COMPLETED)},AuthenticationContext.prototype.getResourceForEndpoint=function(a){if(this.config&&this.config.endpoints)for(var b in this.config.endpoints)if(a.indexOf(b)>-1)return this.config.endpoints[b];if(!(a.indexOf("http://")>-1||a.indexOf("https://")>-1)){if(this.config&&this.config.anonymousEndpoints)for(var c=0;c<this.config.anonymousEndpoints.length;c++)if(a.indexOf(this.config.anonymousEndpoints[c])>-1)return null;return this.config.loginResource}return this._getHostFromUri(a)===this._getHostFromUri(this.config.redirectUri)?this.config.loginResource:null},AuthenticationContext.prototype._getHostFromUri=function(a){var b=String(a).replace(/^(https?:)\/\//,"");return b=b.split("/")[0]},AuthenticationContext.prototype.handleWindowCallback=function(){var a=window.location.hash;if(this.isCallback(a)){var b=this.getRequestInfo(a);this.info("Returned from redirect url"),this.saveTokenFromHash(b);var c=null;if(b.requestType===this.REQUEST_TYPE.RENEW_TOKEN&&window.parent&&window.parent!==window)return this.verbose("Window is in iframe"),c=window.parent.callBackMappedToRenewStates[b.stateResponse],void(c&&c(this._getItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION),b.parameters[this.CONSTANTS.ACCESS_TOKEN]||b.parameters[this.CONSTANTS.ID_TOKEN]));window&&window.oauth2Callback&&(this.verbose("Window is redirecting"),c=this.callback),window.location=this._getItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST)}},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(e){this.error("The returned id_token could not be decoded",e)}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;c>m;m+=4){if(d=b.indexOf(a.charAt(m)),e=b.indexOf(a.charAt(m+1)),f=b.indexOf(a.charAt(m+2)),g=b.indexOf(a.charAt(m+3)),m+2===c-1){h=d<<18|e<<12|f<<6,i=h>>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);if(!c||c.length<4)return this.warn("The returned id_token is not parseable."),null;var d={header:c[1],JWSPayload:c[2],JWSSig:c[3]};return d},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._guid=function(){for(var a="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx",b="0123456789abcdef",c=0,d="",e=0;36>e;e++)"-"!==a[e]&&"4"!==a[e]&&(c=16*Math.random()|0),"x"===a[e]?d+=b[c]:"y"===a[e]?(c&=3,c|=8,d+=b[c]):d+=a[e];return d},AuthenticationContext.prototype._expiresIn=function(a){return this._now()+parseInt(a,10)},AuthenticationContext.prototype._now=function(){return Math.round((new Date).getTime()/1e3)},AuthenticationContext.prototype._addAdalFrame=function(a){if("undefined"!=typeof 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.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",'<iframe name="'+a+'" id="'+a+'" style="display:none"></iframe>');window.frames&&window.frames[a]&&(b=window.frames[a])}return b}},AuthenticationContext.prototype._saveItem=function(a,b){return this.config&&this.config.cacheLocation&&"localStorage"===this.config.cacheLocation?this._supportsLocalStorage()?(localStorage.setItem(a,b),!0):(this.info("Local storage is not supported"),!1):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"localStorage"in window&&window.localStorage}catch(a){return!1}},AuthenticationContext.prototype._supportsSessionStorage=function(){try{return"sessionStorage"in window&&window.sessionStorage}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){if(a<=Logging.level){var d=(new Date).toUTCString(),e="";e=this.config.correlationId?d+":"+this.config.correlationId+"-"+this._libVersion()+"-"+this.CONSTANTS.LEVEL_STRING_MAP[a]+" "+b:d+":"+this._libVersion()+"-"+this.CONSTANTS.LEVEL_STRING_MAP[a]+" "+b,c&&(e+="\nstack:\n"+c.stack),Logging.log(e)}},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._libVersion=function(){return"1.0.11"},"undefined"!=typeof module&&module.exports&&(module.exports=AuthenticationContext,module.exports.inject=function(a){return new AuthenticationContext(a)}),AuthenticationContext}();
//----------------------------------------------------------------------
// AdalJS v1.0.10
// AdalJS v1.0.11
// @preserve Copyright (c) Microsoft Open Technologies, Inc.

@@ -19,12 +19,13 @@ // All Rights Reserved

//----------------------------------------------------------------------
'use strict';
if (typeof module !== 'undefined' && module.exports) {
module.exports.inject = function (conf) {
return new AuthenticationContext(conf);
};
}
(function () {
// ============= Angular modules- Start =============
'use strict';
if (typeof module !== 'undefined' && module.exports) {
module.exports.inject = function (conf) {
return new AuthenticationContext(conf);
};
}
if (angular) {

@@ -69,3 +70,3 @@

// loginresource is used to set authenticated status
// loginResource is used to set authenticated status
updateDataFromCache(_adal.config.loginResource);

@@ -78,3 +79,4 @@ };

var locationChangeHandler = function () {
var locationChangeHandler = function (event, newUrl, oldUrl) {
_adal.verbose('Location change event from ' + oldUrl + ' to ' + newUrl);
var hash = $window.location.hash;

@@ -84,12 +86,6 @@

// callback can come from login or iframe request
_adal.verbose('Processing the hash: ' + hash);
var requestInfo = _adal.getRequestInfo(hash);
_adal.saveTokenFromHash(requestInfo);
if ($location.$$html5) {
$window.location = $window.location.origin + $window.location.pathname;
} else {
$window.location.hash = '';
}
if (requestInfo.requestType !== _adal.REQUEST_TYPE.LOGIN) {

@@ -102,8 +98,11 @@ _adal.callback = $window.parent.AuthenticationContext().callback;

// Return to callback if it is send from iframe
// Return to callback if it is sent from iframe
if (requestInfo.stateMatch) {
if (typeof _adal.callback === 'function') {
// since this is a token renewal request in iFrame, we don't need to proceed with the location change.
event.preventDefault();
// Call within the same context without full page redirect keeps the callback
if (requestInfo.requestType === _adal.REQUEST_TYPE.RENEW_TOKEN) {
// Idtoken or Accestoken can be renewed
// id_token or access_token can be renewed
if (requestInfo.parameters['access_token']) {

@@ -117,3 +116,2 @@ _adal.callback(_adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['access_token']);

_adal.callback(_adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), null);
_adal._renewFailed = true;
return;

@@ -126,21 +124,8 @@ }

if (_oauthData.userName) {
//IDtoken is added as token for the app
$timeout(function () {
// id_token is added as token for the app
updateDataFromCache(_adal.config.loginResource);
$rootScope.userInfo = _oauthData;
// redirect to login requested page
var loginStartPage = _adal._getItem(_adal.CONSTANTS.STORAGE.START_PAGE);
if (loginStartPage) {
// Check to see if any params were stored
var paramsJSON = _adal._getItem(_adal.CONSTANTS.STORAGE.START_PAGE_PARAMS);
if (paramsJSON) {
// If params were stored redirect to the page and then
// initialize the params
var loginStartPageParams = JSON.parse(paramsJSON);
$location.url(loginStartPage).search(loginStartPageParams);
} else {
$location.url(loginStartPage);
}
}
}, 1);
$rootScope.$broadcast('adal:loginSuccess');

@@ -150,2 +135,14 @@ } else {

}
// redirect to login start page
var loginStartPage = _adal._getItem(_adal.CONSTANTS.STORAGE.LOGIN_REQUEST);
if (loginStartPage) {
// prevent the current location change and redirect the user back to the login start page
_adal.verbose('Redirecting to start page: ' + loginStartPage);
event.preventDefault();
if (!$location.$$html5 && loginStartPage.indexOf('#') > -1) {
$location.url(loginStartPage.substring(loginStartPage.indexOf('#') + 1));
}
$window.location = loginStartPage;
}
}

@@ -161,4 +158,4 @@ }

updateDataFromCache(_adal.config.loginResource);
if (!_oauthData.isAuthenticated && _oauthData.userName && !_adal._renewActive && !_adal._renewFailed) {
// Idtoken is expired or not present
if (!_oauthData.isAuthenticated && _oauthData.userName && !_adal._renewActive) {
// id_token is expired or not present
_adal._renewActive = true;

@@ -188,5 +185,5 @@ _adal.acquireToken(_adal.config.loginResource, function (error, tokenOut) {

$location.path(_adal.config.localLoginUrl);
} else {
}
else {
// directly start login flow
_adal._saveItem(_adal.CONSTANTS.STORAGE.START_PAGE, $location.$$url);
_adal.info('Start login at:' + window.location.href);

@@ -216,5 +213,7 @@ $rootScope.$broadcast('adal:loginRedirect');

if (isADLoginRequired(nextRoute.$$route, _adal.config)) {
if (!_oauthData.isAuthenticated && !_adal._renewActive) {
_adal.info('Route change event for:' + $location.$$url);
loginHandler();
if (!_oauthData.isAuthenticated) {
if (!_adal._renewActive && !_adal.loginInProgress()) {
_adal.info('Route change event for:' + $location.$$url);
loginHandler();
}
}

@@ -233,14 +232,7 @@ }

if (isADLoginRequired(toState, _adal.config)) {
if (!_oauthData.isAuthenticated && !_adal._renewActive) {
// $location.$$url is set as the page we are coming from
// Update it so we can store the actual location we want to
// redirect to upon returning
$location.$$url = toState.url;
// Parameters are not stored in the url on stateChange so
// we store them
_adal._saveItem(_adal.CONSTANTS.STORAGE.START_PAGE_PARAMS, JSON.stringify(toParams));
_adal.info('State change event for:' + $location.$$url);
loginHandler();
if (!_oauthData.isAuthenticated) {
if (!_adal._renewActive && !_adal.loginInProgress()) {
_adal.info('State change event for:' + $location.$$url);
loginHandler();
}
}

@@ -256,2 +248,13 @@ }

var stateChangeErrorHandler = function (event, toState, toParams, fromState, fromParams, error) {
_adal.verbose("State change error occured. Error: " + 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) {
_adal.info("Setting defaultPrevented to true if state change error occured because adal rejected a request. Error: " + error.data);
event.preventDefault();
}
};
// Route change event tracking to receive fragment and also auto renew tokens

@@ -264,2 +267,4 @@ $rootScope.$on('$routeChangeStart', routeChangeHandler);

$rootScope.$on('$stateChangeError', stateChangeErrorHandler);
updateDataFromCache(_adal.config.loginResource);

@@ -272,3 +277,3 @@ $rootScope.userInfo = _oauthData;

login: function () {
_adal.login();
loginHandler();
},

@@ -341,7 +346,3 @@ loginInProgress: function () {

// This interceptor needs to load service, but dependeny definition causes circular reference error.
// Loading with injector is suggested at github. https://github.com/angular/angular.js/issues/2367
config.headers = config.headers || {};
var resource = authService.getResourceForEndpoint(config.url);

@@ -352,23 +353,26 @@ authService.verbose('Url: ' + config.url + ' maps to resource: ' + resource);

}
var tokenStored = authService.getCachedToken(resource);
if (tokenStored) {
authService.info('Token is avaliable for this url ' + config.url);
authService.info('Token is available for this url ' + config.url);
// check endpoint mapping if provided
config.headers.Authorization = 'Bearer ' + tokenStored;
return config;
} else {
}
else {
// Cancel request if login is starting
if (authService.loginInProgress()) {
authService.info('login already start.');
return $q.reject('login in progress, cancelling the request');
} else {
authService.info('login is in progress.');
config.data = 'login in progress, cancelling the request for ' + config.url;
return $q.reject(config);
}
else {
// delayed request to return after iframe completes
var delayedRequest = $q.defer();
authService.acquireToken(resource).then(function (token) {
authService.verbose('Token is avaliable');
authService.verbose('Token is available');
config.headers.Authorization = 'Bearer ' + token;
delayedRequest.resolve(config);
}, function (err) {
delayedRequest.reject(err);
config.data = err;
delayedRequest.reject(config);
});

@@ -384,3 +388,3 @@

responseError: function (rejection) {
authService.info('Getting error in the response');
authService.info('Getting error in the response.');
if (rejection) {

@@ -387,0 +391,0 @@ if (rejection.status === 401) {

@@ -1,3 +0,3 @@

//----------------------------------------------------------------------
// AdalJS v1.0.10
//----------------------------------------------------------------------
// AdalJS v1.0.11
// @preserve Copyright (c) Microsoft Open Technologies, Inc.

@@ -19,609 +19,624 @@ // All Rights Reserved

//----------------------------------------------------------------------
'use strict';
// node.js usage for tests
var Logging = {
level: 0,
log: function () { }
};
var AuthenticationContext = (function () {
var AuthenticationContext;
if (typeof module !== 'undefined' && module.exports) {
module.exports.inject = function (conf) {
return new AuthenticationContext(conf);
};
}
'use strict';
/**
* Config information
* @public
* @class Config
* @property {tenant} Your target tenant
* @property {clientId} Identifier assigned to your app by Azure Active Directory
* @property {redirectUri} Endpoint at which you expect to receive tokens
* @property {instance} Azure Active Directory Instance(default:https://login.microsoftonline.com/)
* @property {endpoints} Collection of {Endpoint-ResourceId} used for autmatically attaching tokens in webApi calls
*/
/**
* User information from idtoken.
* @class User
* @property {string} userName - username assigned from upn or email.
* @property {object} profile - properties parsed from idtoken.
*/
/**
* Creates a new AuthenticationContext object.
* @constructor
* @param {object} config Configuration options for AuthenticationContext
*
**/
AuthenticationContext = function (config) {
/**
* Enum for request type
* @enum {string}
* Config information
* @public
* @class Config
* @property {tenant} Your target tenant
* @property {clientId} Identifier assigned to your app by Azure Active Directory
* @property {redirectUri} Endpoint at which you expect to receive tokens
* @property {instance} Azure Active Directory Instance(default:https://login.microsoftonline.com/)
* @property {endpoints} Collection of {Endpoint-ResourceId} used for autmatically attaching tokens in webApi calls
*/
this.REQUEST_TYPE = {
LOGIN: 'LOGIN',
RENEW_TOKEN: 'RENEW_TOKEN',
UNKNOWN: 'UNKNOWN'
};
/**
* Enum for storage constants
* @enum {string}
* User information from idtoken.
* @class User
* @property {string} userName - username assigned from upn or email.
* @property {object} profile - properties parsed from idtoken.
*/
this.CONSTANTS = {
ACCESS_TOKEN: 'access_token',
EXPIRES_IN: 'expires_in',
ID_TOKEN: 'id_token',
ERROR_DESCRIPTION: 'error_description',
SESSION_STATE: 'session_state',
STORAGE: {
TOKEN_KEYS: 'adal.token.keys',
ACCESS_TOKEN_KEY: 'adal.access.token.key',
EXPIRATION_KEY: 'adal.expiration.key',
START_PAGE: 'adal.start.page',
START_PAGE_PARAMS: 'adal.start.page.params',
STATE_LOGIN: 'adal.state.login',
STATE_RENEW: 'adal.state.renew',
STATE_RENEW_RESOURCE: 'adal.state.renew.resource',
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'
},
RESOURCE_DELIMETER: '|',
ERR_MESSAGES: {
NO_TOKEN: 'User is not authorized'
},
LOGGING_LEVEL: {
ERROR: 0,
WARN: 1,
INFO: 2,
VERBOSE: 3
},
LEVEL_STRING_MAP: {
0: 'ERROR:',
1: 'WARNING:',
2: 'INFO:',
3: 'VERBOSE:'
}
};
if (AuthenticationContext.prototype._singletonInstance) {
return AuthenticationContext.prototype._singletonInstance;
}
AuthenticationContext.prototype._singletonInstance = this;
/**
* Creates a new AuthenticationContext object.
* @constructor
* @param {object} config Configuration options for AuthenticationContext
*
**/
AuthenticationContext = function (config) {
/**
* Enum for request type
* @enum {string}
*/
this.REQUEST_TYPE = {
LOGIN: 'LOGIN',
RENEW_TOKEN: 'RENEW_TOKEN',
UNKNOWN: 'UNKNOWN'
};
// public
this.instance = 'https://login.microsoftonline.com/';
this.config = {};
this.callback = null;
this.popUp = false;
/**
* Enum for storage constants
* @enum {string}
*/
this.CONSTANTS = {
ACCESS_TOKEN: 'access_token',
EXPIRES_IN: 'expires_in',
ID_TOKEN: 'id_token',
ERROR_DESCRIPTION: 'error_description',
SESSION_STATE: 'session_state',
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',
STATE_RENEW_RESOURCE: 'adal.state.renew.resource',
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'
},
RESOURCE_DELIMETER: '|',
ERR_MESSAGES: {
NO_TOKEN: 'User is not authorized'
},
LOADFRAME_TIMEOUT: '6000',
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:'
}
};
// private
this._user = null;
this._activeRenewals = {};
this._loginInProgress = false;
this._renewStates = [];
if (AuthenticationContext.prototype._singletonInstance) {
return AuthenticationContext.prototype._singletonInstance;
}
AuthenticationContext.prototype._singletonInstance = this;
window.callBackMappedToRenewStates = {};
window.callBacksMappedToRenewStates = {};
// public
this.instance = 'https://login.microsoftonline.com/';
this.config = {};
this.callback = null;
this.popUp = false;
// validate before constructor assignments
if (config.displayCall && typeof config.displayCall !== 'function') {
throw new Error('displayCall is not a function');
}
// private
this._user = null;
this._activeRenewals = {};
this._loginInProgress = false;
this._renewStates = [];
if (!config.clientId) {
throw new Error('clientId is required');
}
window.callBackMappedToRenewStates = {};
window.callBacksMappedToRenewStates = {};
if (!config.correlationId) {
config.correlationId = this._guid();
}
// validate before constructor assignments
if (config.displayCall && typeof config.displayCall !== 'function') {
throw new Error('displayCall is not a function');
}
this.config = this._cloneConfig(config);
if (!config.clientId) {
throw new Error('clientId is required');
}
// App can request idtoken for itself using clientid as resource
if (!this.config.loginResource) {
this.config.loginResource = this.config.clientId;
}
this.config = this._cloneConfig(config);
if (!this.config.redirectUri) {
this.config.redirectUri = window.location.href;
}
};
if (this.config.instance) {
this.instance = this.config.instance;
}
/**
* Gets initial Idtoken for the app backend
* Saves the resulting Idtoken in localStorage.
*/
AuthenticationContext.prototype.login = function () {
// Token is not present and user needs to login
var expectedState = this._guid();
this.config.state = expectedState;
this._idTokenNonce = this._guid();
this.verbose('Expected state: ' + expectedState + ' startPage:' + window.location);
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST, window.location);
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN, expectedState);
this._saveItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN, this._idTokenNonce);
this._saveItem(this.CONSTANTS.STORAGE.ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, '');
// App can request idtoken for itself using clientid as resource
if (!this.config.loginResource) {
this.config.loginResource = this.config.clientId;
}
if (!this.config.redirectUri) {
this.config.redirectUri = window.location.href;
}
var urlNavigate = this._getNavigateUrl('id_token', null) + '&nonce=' + encodeURIComponent(this._idTokenNonce);
this.frameCallInProgress = false;
this._loginInProgress = true;
if (this.config.displayCall) {
// User defined way of handling the navigation
this.config.displayCall(urlNavigate);
} else {
this.promptUser(urlNavigate);
}
// callback from redirected page will receive fragment. It needs to call oauth2Callback
};
if (!this.config.anonymousEndpoints) {
this.config.anonymousEndpoints = [];
}
};
AuthenticationContext.prototype.loginInProgress = function () {
return this._loginInProgress;
};
window.Logging = {
level: 0,
log: function (message) { }
};
AuthenticationContext.prototype._hasResource = function (key) {
var keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS);
return keys && !this._isEmpty(keys) && (keys.indexOf(key + this.CONSTANTS.RESOURCE_DELIMETER) > -1);
};
/**
* Gets initial Idtoken for the app backend
* Saves the resulting Idtoken in localStorage.
*/
AuthenticationContext.prototype.login = function () {
// Token is not present and user needs to login
var expectedState = this._guid();
this.config.state = expectedState;
this._idTokenNonce = this._guid();
this.verbose('Expected state: ' + expectedState + ' startPage:' + window.location);
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST, window.location);
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN, expectedState);
this._saveItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN, this._idTokenNonce);
this._saveItem(this.CONSTANTS.STORAGE.ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, '');
/**
* Gets token for the specified resource from local storage cache
* @param {string} resource A URI that identifies the resource for which the token is valid.
* @returns {string} token if exists and not expired or null
*/
AuthenticationContext.prototype.getCachedToken = function (resource) {
if (!this._hasResource(resource)) {
return null;
}
var token = this._getItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource);
var expired = this._getItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource);
var urlNavigate = this._getNavigateUrl('id_token', null) + '&nonce=' + encodeURIComponent(this._idTokenNonce);
this.frameCallInProgress = false;
this._loginInProgress = true;
if (this.config.displayCall) {
// User defined way of handling the navigation
this.config.displayCall(urlNavigate);
} else {
this.promptUser(urlNavigate);
}
// callback from redirected page will receive fragment. It needs to call oauth2Callback
};
// If expiration is within offset, it will force renew
var offset = this.config.expireOffsetSeconds || 120;
AuthenticationContext.prototype.loginInProgress = function () {
return this._loginInProgress;
};
if (expired && (expired > this._now() + offset)) {
return token;
} else {
this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource, '');
this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, 0);
return null;
}
};
AuthenticationContext.prototype._hasResource = function (key) {
var keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS);
return keys && !this._isEmpty(keys) && (keys.indexOf(key + this.CONSTANTS.RESOURCE_DELIMETER) > -1);
};
/**
* Retrieves and parse idToken from localstorage
* @returns {User} user object
*/
AuthenticationContext.prototype.getCachedUser = function () {
if (this._user) {
return this._user;
}
/**
* Gets token for the specified resource from local storage cache
* @param {string} resource A URI that identifies the resource for which the token is valid.
* @returns {string} token if exists and not expired or null
*/
AuthenticationContext.prototype.getCachedToken = function (resource) {
if (!this._hasResource(resource)) {
return null;
}
var idtoken = this._getItem(this.CONSTANTS.STORAGE.IDTOKEN);
this._user = this._createUser(idtoken);
return this._user;
};
var token = this._getItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource);
var expired = this._getItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource);
AuthenticationContext.prototype.registerCallback = function (expectedState, resource, callback) {
this._activeRenewals[resource] = expectedState;
if (!window.callBacksMappedToRenewStates[expectedState]) {
window.callBacksMappedToRenewStates[expectedState] = [];
}
var self = this;
window.callBacksMappedToRenewStates[expectedState].push(callback);
if (!window.callBackMappedToRenewStates[expectedState]) {
window.callBackMappedToRenewStates[expectedState] = function (message, token) {
for (var i = 0; i < window.callBacksMappedToRenewStates[expectedState].length; ++i) {
window.callBacksMappedToRenewStates[expectedState][i](message, token);
}
self._activeRenewals[resource] = null;
window.callBacksMappedToRenewStates[expectedState] = null;
window.callBackMappedToRenewStates[expectedState] = null;
};
}
};
// If expiration is within offset, it will force renew
var offset = this.config.expireOffsetSeconds || 120;
// var errorResponse = {error:'', errorDescription:''};
// var token = 'string token';
// callback(errorResponse, token)
// with callback
/**
* Acquires access token with hidden iframe
* @param {string} resource ResourceUri identifying the target resource
* @returns {string} access token if request is successfull
*/
AuthenticationContext.prototype._renewToken = function (resource, callback) {
// use iframe to try refresh token
// 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;
this._idTokenNonce = this._guid();
this.config.state = expectedState;
// renew happens in iframe, so it keeps javascript context
this._renewStates.push(expectedState);
if (expired && (expired > this._now() + offset)) {
return token;
} else {
this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource, '');
this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, 0);
return null;
}
};
/**
* Retrieves and parse idToken from localstorage
* @returns {User} user object
*/
AuthenticationContext.prototype.getCachedUser = function () {
if (this._user) {
return this._user;
}
this.verbose('Renew token Expected state: ' + expectedState);
var urlNavigate = this._getNavigateUrl('token', resource) + '&prompt=none&login_hint=' + encodeURIComponent(this._user.userName);
var idtoken = this._getItem(this.CONSTANTS.STORAGE.IDTOKEN);
this._user = this._createUser(idtoken);
return this._user;
};
// don't add domain_hint twice if user provided it in the extraQueryParameter value
if (!this._urlContainsQueryStringParameter("domain_hint", urlNavigate)) {
urlNavigate += '&domain_hint=' + encodeURIComponent(this._getDomainHint());
}
AuthenticationContext.prototype.registerCallback = function (expectedState, resource, callback) {
this._activeRenewals[resource] = expectedState;
if (!window.callBacksMappedToRenewStates[expectedState]) {
window.callBacksMappedToRenewStates[expectedState] = [];
}
var self = this;
window.callBacksMappedToRenewStates[expectedState].push(callback);
if (!window.callBackMappedToRenewStates[expectedState]) {
window.callBackMappedToRenewStates[expectedState] = function (message, token) {
for (var i = 0; i < window.callBacksMappedToRenewStates[expectedState].length; ++i) {
window.callBacksMappedToRenewStates[expectedState][i](message, token);
}
self._activeRenewals[resource] = null;
window.callBacksMappedToRenewStates[expectedState] = null;
window.callBackMappedToRenewStates[expectedState] = null;
};
}
};
urlNavigate += '&nonce=' + encodeURIComponent(this._idTokenNonce);
this.callback = callback;
this.registerCallback(expectedState, resource, callback);
this.idTokenNonce = null;
this.verbose('Navigate to:' + urlNavigate);
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST, '');
frameHandle.src = 'about:blank';
this._loadFrame(urlNavigate, 'adalRenewFrame' + resource);
};
// var errorResponse = {error:'', error_description:''};
// var token = 'string token';
// callback(errorResponse, token)
// with callback
/**
* Acquires access token with hidden iframe
* @param {string} resource ResourceUri identifying the target resource
* @returns {string} access token if request is successful
*/
AuthenticationContext.prototype._renewToken = function (resource, callback) {
// use iframe to try refresh token
// 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;
this.config.state = expectedState;
// renew happens in iframe, so it keeps javascript context
this._renewStates.push(expectedState);
AuthenticationContext.prototype._renewIdToken = function (callback) {
// use iframe to try refresh token
this.info('renewIdToken is called');
var frameHandle = this._addAdalFrame('adalIdTokenFrame');
var expectedState = this._guid() + '|' + this.config.clientId;
this._idTokenNonce = this._guid();
this._saveItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN, this._idTokenNonce);
this.config.state = expectedState;
// renew happens in iframe, so it keeps javascript context
this._renewStates.push(expectedState);
this.verbose('Renew token Expected state: ' + expectedState);
var urlNavigate = this._getNavigateUrl('token', resource) + '&prompt=none';
urlNavigate = this._addHintParameters(urlNavigate);
this.verbose('Renew Idtoken Expected state: ' + expectedState);
var urlNavigate = this._getNavigateUrl('id_token', null) + '&prompt=none&login_hint=' + encodeURIComponent(this._user.userName);
this.callback = callback;
this.registerCallback(expectedState, resource, callback);
this.verbose('Navigate to:' + urlNavigate);
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST, '');
frameHandle.src = 'about:blank';
this._loadFrameTimeout(urlNavigate, 'adalRenewFrame' + resource, resource);
// don't add domain_hint twice if user provided it in the extraQueryParameter value
if (!this._urlContainsQueryStringParameter("domain_hint", urlNavigate)) {
urlNavigate += '&domain_hint=' + encodeURIComponent(this._getDomainHint());
}
};
urlNavigate += '&nonce=' + encodeURIComponent(this._idTokenNonce);
this.registerCallback(expectedState, this.config.clientId, callback);
this.idTokenNonce = null;
this.verbose('Navigate to:' + urlNavigate);
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST, '');
frameHandle.src = 'about:blank';
this._loadFrame(urlNavigate, 'adalIdTokenFrame');
};
AuthenticationContext.prototype._renewIdToken = function (callback) {
// use iframe to try refresh token
this.info('renewIdToken is called');
var frameHandle = this._addAdalFrame('adalIdTokenFrame');
var expectedState = this._guid() + '|' + this.config.clientId;
this._idTokenNonce = this._guid();
this._saveItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN, this._idTokenNonce);
this.config.state = expectedState;
// renew happens in iframe, so it keeps javascript context
this._renewStates.push(expectedState);
AuthenticationContext.prototype._urlContainsQueryStringParameter = function (name, url) {
// regex to detect pattern of a ? or & followed by the name parameter and an equals character
var regex = new RegExp("[\\?&]" + name + "=");
return regex.test(url);
}
this.verbose('Renew Idtoken Expected state: ' + expectedState);
var urlNavigate = this._getNavigateUrl('id_token', null) + '&prompt=none';
urlNavigate = this._addHintParameters(urlNavigate);
AuthenticationContext.prototype._loadFrame = function (urlNavigate, frameName) {
// This trick overcomes iframe navigation in IE
// IE does not load the page consistently in iframe
var self = this;
self.info('LoadFrame: ' + frameName);
var frameCheck = frameName;
setTimeout(function () {
var frameHandle = self._addAdalFrame(frameCheck);
if (frameHandle.src === '' || frameHandle.src === 'about:blank') {
frameHandle.src = urlNavigate;
self._loadFrame(urlNavigate, frameCheck);
}
}, 500);
};
urlNavigate += '&nonce=' + encodeURIComponent(this._idTokenNonce);
this.registerCallback(expectedState, this.config.clientId, callback);
this.idTokenNonce = null;
this.verbose('Navigate to:' + urlNavigate);
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST, '');
frameHandle.src = 'about:blank';
this._loadFrameTimeout(urlNavigate, 'adalIdTokenFrame', this.config.clientId);
};
/**
* Acquire token from cache if not expired and available. Acquires token from iframe if expired.
* @param {string} resource ResourceUri identifying the target resource
* @param {requestCallback} callback
*/
AuthenticationContext.prototype.acquireToken = function (resource, callback) {
if (this._isEmpty(resource)) {
this.warn('resource is required');
callback('resource is required', null);
return;
AuthenticationContext.prototype._urlContainsQueryStringParameter = function (name, url) {
// regex to detect pattern of a ? or & followed by the name parameter and an equals character
var regex = new RegExp("[\\?&]" + name + "=");
return regex.test(url);
}
var token = this.getCachedToken(resource);
if (token) {
this.info('Token is already in cache for resource:' + resource);
callback(null, token);
return;
}
// Calling _loadFrame but with a timeout to signal failure in loadframeStatus. Callbacks are left
// registered when network errors occur and subsequent token requests for same resource are registered to the pending request
AuthenticationContext.prototype._loadFrameTimeout = function (urlNavigation, frameName, resource) {
//set iframe session to pending
this.verbose('Set loading state to pending for: ' + resource);
this._saveItem(this.CONSTANTS.STORAGE.RENEW_STATUS + resource, this.CONSTANTS.TOKEN_RENEW_STATUS_IN_PROGRESS);
this._loadFrame(urlNavigation, frameName);
var self = this;
setTimeout(function () {
if (self._getItem(self.CONSTANTS.STORAGE.RENEW_STATUS + resource) === self.CONSTANTS.TOKEN_RENEW_STATUS_IN_PROGRESS) {
// fail the iframe session if it's in pending state
self.verbose('Loading frame has timed out after: ' + (self.CONSTANTS.LOADFRAME_TIMEOUT / 1000) + ' seconds for resource ' + resource);
var expectedState = self._activeRenewals[resource];
if (expectedState && window.callBackMappedToRenewStates[expectedState]) {
window.callBackMappedToRenewStates[expectedState]('Token renewal operation failed due to timeout', null);
}
if (!this._user) {
this.warn('User login is required');
callback('User login is required', null);
return;
self._saveItem(self.CONSTANTS.STORAGE.RENEW_STATUS + resource, self.CONSTANTS.TOKEN_RENEW_STATUS_CANCELED);
}
}, self.CONSTANTS.LOADFRAME_TIMEOUT);
}
// refresh attept with iframe
//Already renewing for this resource, callback when we get the token.
if (this._activeRenewals[resource]) {
//Active renewals contains the state for each renewal.
this.registerCallback(this._activeRenewals[resource], resource, callback);
}
else {
if (resource === this.config.clientId) {
// App uses idtoken to send to api endpoints
// Default resource is tracked as clientid to store this token
this.verbose('renewing idtoken');
this._renewIdToken(callback);
} else {
this._renewToken(resource, callback);
AuthenticationContext.prototype._loadFrame = function (urlNavigate, frameName) {
// This trick overcomes iframe navigation in IE
// IE does not load the page consistently in iframe
var self = this;
self.info('LoadFrame: ' + frameName);
var frameCheck = frameName;
setTimeout(function () {
var frameHandle = self._addAdalFrame(frameCheck);
if (frameHandle.src === '' || frameHandle.src === 'about:blank') {
frameHandle.src = urlNavigate;
self._loadFrame(urlNavigate, frameCheck);
}
}, 500);
};
/**
* Acquire token from cache if not expired and available. Acquires token from iframe if expired.
* @param {string} resource ResourceUri identifying the target resource
* @param {requestCallback} callback
*/
AuthenticationContext.prototype.acquireToken = function (resource, callback) {
if (this._isEmpty(resource)) {
this.warn('resource is required');
callback('resource is required', null);
return;
}
}
};
/**
* Redirect the Browser to Azure AD Authorization endpoint
* @param {string} urlNavigate The authorization request url
*/
AuthenticationContext.prototype.promptUser = function (urlNavigate) {
if (urlNavigate) {
this.info('Navigate to:' + urlNavigate);
window.location.replace(urlNavigate);
} else {
this.info('Navigate url is empty');
}
};
var token = this.getCachedToken(resource);
if (token) {
this.info('Token is already in cache for resource:' + resource);
callback(null, token);
return;
}
/**
* Clear cache items.
*/
AuthenticationContext.prototype.clearCache = function () {
this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY, '');
this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY, 0);
this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE, '');
this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN, '');
this._renewStates = [];
this._saveItem(this.CONSTANTS.STORAGE.START_PAGE, '');
this._saveItem(this.CONSTANTS.STORAGE.START_PAGE_PARAMS, '');
this._saveItem(this.CONSTANTS.STORAGE.USERNAME, '');
this._saveItem(this.CONSTANTS.STORAGE.IDTOKEN, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, '');
var keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS);
if (!this._user) {
this.warn('User login is required');
callback('User login is required', null);
return;
}
if (!this._isEmpty(keys)) {
keys = keys.split(this.CONSTANTS.RESOURCE_DELIMETER);
for (var i = 0; i < keys.length; i++) {
this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + keys[i], '');
this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + keys[i], 0);
// refresh attept with iframe
//Already renewing for this resource, callback when we get the token.
if (this._activeRenewals[resource]) {
//Active renewals contains the state for each renewal.
this.registerCallback(this._activeRenewals[resource], resource, callback);
}
}
this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, '');
};
else {
if (resource === this.config.clientId) {
// App uses idtoken to send to api endpoints
// Default resource is tracked as clientid to store this token
this.verbose('renewing idtoken');
this._renewIdToken(callback);
} else {
this._renewToken(resource, callback);
}
}
};
/**
* Clear cache items for a resource.
*/
AuthenticationContext.prototype.clearCacheForResource = function (resource) {
this._saveItem(this.CONSTANTS.STORAGE.STATE_RENEW, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, '');
if (this._hasResource(resource)) {
this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource, '');
this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, 0);
}
};
/**
* Redirect the Browser to Azure AD Authorization endpoint
* @param {string} urlNavigate The authorization request url
*/
AuthenticationContext.prototype.promptUser = function (urlNavigate) {
if (urlNavigate) {
this.info('Navigate to:' + urlNavigate);
window.location.replace(urlNavigate);
} else {
this.info('Navigate url is empty');
}
};
/**
* Logout user will redirect page to logout endpoint.
* After logout, it will redirect to post_logout page if provided.
*/
AuthenticationContext.prototype.logOut = function () {
this.clearCache();
var tenant = 'common';
var logout = '';
this._user = null;
if (this.config.tenant) {
tenant = this.config.tenant;
}
/**
* Clear cache items.
*/
AuthenticationContext.prototype.clearCache = function () {
this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY, '');
this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY, 0);
this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE, '');
this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN, '');
this._renewStates = [];
this._saveItem(this.CONSTANTS.STORAGE.USERNAME, '');
this._saveItem(this.CONSTANTS.STORAGE.IDTOKEN, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, '');
var keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS);
if (this.config.instance) {
this.instance = this.config.instance;
}
if (!this._isEmpty(keys)) {
keys = keys.split(this.CONSTANTS.RESOURCE_DELIMETER);
for (var i = 0; i < keys.length; i++) {
this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + keys[i], '');
this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + keys[i], 0);
}
}
this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, '');
};
if (this.config.postLogoutRedirectUri) {
logout = 'post_logout_redirect_uri=' + encodeURIComponent(this.config.postLogoutRedirectUri);
}
/**
* Clear cache items for a resource.
*/
AuthenticationContext.prototype.clearCacheForResource = function (resource) {
this._saveItem(this.CONSTANTS.STORAGE.STATE_RENEW, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, '');
if (this._hasResource(resource)) {
this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource, '');
this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, 0);
}
};
var urlNavigate = this.instance + tenant + '/oauth2/logout?' + logout;
this.info('Logout navigate to: ' + urlNavigate);
this.promptUser(urlNavigate);
};
/**
* Logout user will redirect page to logout endpoint.
* After logout, it will redirect to post_logout page if provided.
*/
AuthenticationContext.prototype.logOut = function () {
this.clearCache();
var tenant = 'common';
var logout = '';
this._user = null;
if (this.config.tenant) {
tenant = this.config.tenant;
}
AuthenticationContext.prototype._isEmpty = function (str) {
return (typeof str === 'undefined' || !str || 0 === str.length);
};
if (this.config.postLogoutRedirectUri) {
logout = 'post_logout_redirect_uri=' + encodeURIComponent(this.config.postLogoutRedirectUri);
}
/**
* This callback is displayed as part of the Requester class.
* @callback requestCallback
* @param {string} error
* @param {User} user
*/
var urlNavigate = this.instance + tenant + '/oauth2/logout?' + logout;
this.info('Logout navigate to: ' + urlNavigate);
this.promptUser(urlNavigate);
};
/**
* Gets a user profile
* @param {requestCallback} cb - The callback that handles the response.
*/
AuthenticationContext.prototype.getUser = function (callback) {
// IDToken is first call
if (typeof callback !== 'function') {
throw new Error('callback is not a function');
}
AuthenticationContext.prototype._isEmpty = function (str) {
return (typeof str === 'undefined' || !str || 0 === str.length);
};
this.callback = callback;
/**
* This callback is displayed as part of the Requester class.
* @callback requestCallback
* @param {string} error
* @param {User} user
*/
// user in memory
if (this._user) {
this.callback(null, this._user);
return;
}
/**
* Gets a user profile
* @param {requestCallback} cb - The callback that handles the response.
*/
AuthenticationContext.prototype.getUser = function (callback) {
// IDToken is first call
if (typeof callback !== 'function') {
throw new Error('callback is not a function');
}
// frame is used to get idtoken
var idtoken = this._getItem(this.CONSTANTS.STORAGE.IDTOKEN);
if (!this._isEmpty(idtoken)) {
this.info('User exists in cache: ');
this._user = this._createUser(idtoken);
this.callback(null, this._user);
} else {
this.warn('User information is not available');
this.callback('User information is not available');
}
};
this.callback = callback;
AuthenticationContext.prototype._getDomainHint = function () {
if (this._user && this._user.userName && this._user.userName.indexOf('@') > -1) {
var parts = this._user.userName.split('@');
// local part can include @ in quotes. Sending last part handles that.
return parts[parts.length - 1];
}
// user in memory
if (this._user) {
this.callback(null, this._user);
return;
}
return '';
};
// frame is used to get idtoken
var idtoken = this._getItem(this.CONSTANTS.STORAGE.IDTOKEN);
if (!this._isEmpty(idtoken)) {
this.info('User exists in cache: ');
this._user = this._createUser(idtoken);
this.callback(null, this._user);
} else {
this.warn('User information is not available');
this.callback('User information is not available');
}
};
AuthenticationContext.prototype._createUser = function (idToken) {
var user = null;
var parsedJson = this._extractIdToken(idToken);
if (parsedJson && parsedJson.hasOwnProperty('aud')) {
AuthenticationContext.prototype._addHintParameters = function (urlNavigate) {
// include hint params only if upn is present
if (this._user && this._user.profile && this._user.profile.hasOwnProperty('upn')) {
if (parsedJson.aud.toLowerCase() === this.config.clientId.toLowerCase()) {
// add login_hint
urlNavigate += '&login_hint=' + encodeURIComponent(this._user.profile.upn);
user = {
userName: '',
profile: parsedJson
};
if (parsedJson.hasOwnProperty('upn')) {
user.userName = parsedJson.upn;
} else if (parsedJson.hasOwnProperty('email')) {
user.userName = parsedJson.email;
// don't add domain_hint twice if user provided it in the extraQueryParameter value
if (!this._urlContainsQueryStringParameter("domain_hint", urlNavigate) && this._user.profile.upn.indexOf('@') > -1) {
var parts = this._user.profile.upn.split('@');
// local part can include @ in quotes. Sending last part handles that.
urlNavigate += '&domain_hint=' + encodeURIComponent(parts[parts.length - 1]);
}
} else {
this.warn('IdToken has invalid aud field');
}
return urlNavigate;
}
return user;
};
AuthenticationContext.prototype._createUser = function (idToken) {
var user = null;
var parsedJson = this._extractIdToken(idToken);
if (parsedJson && parsedJson.hasOwnProperty('aud')) {
if (parsedJson.aud.toLowerCase() === this.config.clientId.toLowerCase()) {
AuthenticationContext.prototype._getHash = function (hash) {
if (hash.indexOf('#/') > -1) {
hash = hash.substring(hash.indexOf('#/') + 2);
} else if (hash.indexOf('#') > -1) {
hash = hash.substring(1);
}
user = {
userName: '',
profile: parsedJson
};
return hash;
};
if (parsedJson.hasOwnProperty('upn')) {
user.userName = parsedJson.upn;
} else if (parsedJson.hasOwnProperty('email')) {
user.userName = parsedJson.email;
}
} else {
this.warn('IdToken has invalid aud field');
}
/**
* Checks if hash contains access token or id token or error_description
* @param {string} hash - Hash passed from redirect page
* @returns {Boolean}
*/
AuthenticationContext.prototype.isCallback = function (hash) {
hash = this._getHash(hash);
var parameters = this._deserialize(hash);
return (
parameters.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION) ||
parameters.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN) ||
parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)
);
};
}
/**
* Gets login error
* @returns {string} error message related to login
*/
AuthenticationContext.prototype.getLoginError = function () {
return this._getItem(this.CONSTANTS.STORAGE.LOGIN_ERROR);
};
return user;
};
/**
* Gets requestInfo from given hash.
* @returns {string} error message related to login
*/
AuthenticationContext.prototype.getRequestInfo = function (hash) {
hash = this._getHash(hash);
var parameters = this._deserialize(hash);
var requestInfo = {
valid: false,
parameters: {},
stateMatch: false,
stateResponse: '',
requestType: this.REQUEST_TYPE.UNKNOWN
AuthenticationContext.prototype._getHash = function (hash) {
if (hash.indexOf('#/') > -1) {
hash = hash.substring(hash.indexOf('#/') + 2);
} else if (hash.indexOf('#') > -1) {
hash = hash.substring(1);
}
return hash;
};
if (parameters) {
requestInfo.parameters = parameters;
if (parameters.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION) ||
/**
* Checks if hash contains access token or id token or error_description
* @param {string} hash - Hash passed from redirect page
* @returns {Boolean}
*/
AuthenticationContext.prototype.isCallback = function (hash) {
hash = this._getHash(hash);
var parameters = this._deserialize(hash);
return (
parameters.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION) ||
parameters.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN) ||
parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)) {
parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)
);
};
requestInfo.valid = true;
/**
* Gets login error
* @returns {string} error message related to login
*/
AuthenticationContext.prototype.getLoginError = function () {
return this._getItem(this.CONSTANTS.STORAGE.LOGIN_ERROR);
};
// which call
var stateResponse = '';
if (parameters.hasOwnProperty('state')) {
this.verbose('State: ' + parameters.state);
stateResponse = parameters.state;
} else {
this.warn('No state returned');
return requestInfo;
}
/**
* Gets requestInfo from given hash.
* @returns {string} error message related to login
*/
AuthenticationContext.prototype.getRequestInfo = function (hash) {
hash = this._getHash(hash);
var parameters = this._deserialize(hash);
var requestInfo = {
valid: false,
parameters: {},
stateMatch: false,
stateResponse: '',
requestType: this.REQUEST_TYPE.UNKNOWN
};
if (parameters) {
requestInfo.parameters = parameters;
if (parameters.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION) ||
parameters.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN) ||
parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)) {
requestInfo.stateResponse = stateResponse;
requestInfo.valid = true;
// async calls can fire iframe and login request at the same time if developer does not use the API as expected
// incoming callback needs to be looked up to find the request type
if (stateResponse === this._getItem(this.CONSTANTS.STORAGE.STATE_LOGIN)) {
requestInfo.requestType = this.REQUEST_TYPE.LOGIN;
requestInfo.stateMatch = true;
return requestInfo;
}
// which call
var stateResponse = '';
if (parameters.hasOwnProperty('state')) {
this.verbose('State: ' + parameters.state);
stateResponse = parameters.state;
} else {
this.warn('No state returned');
return requestInfo;
}
// external api requests may have many renewtoken requests for different resource
if (!requestInfo.stateMatch && window.parent && window.parent.AuthenticationContext()) {
var statesInParentContext = window.parent.AuthenticationContext()._renewStates;
for (var i = 0; i < statesInParentContext.length; i++) {
if (statesInParentContext[i] === requestInfo.stateResponse) {
requestInfo.requestType = this.REQUEST_TYPE.RENEW_TOKEN;
requestInfo.stateMatch = true;
break;
requestInfo.stateResponse = stateResponse;
// async calls can fire iframe and login request at the same time if developer does not use the API as expected
// incoming callback needs to be looked up to find the request type
if (stateResponse === this._getItem(this.CONSTANTS.STORAGE.STATE_LOGIN)) {
requestInfo.requestType = this.REQUEST_TYPE.LOGIN;
requestInfo.stateMatch = true;
return requestInfo;
}
// external api requests may have many renewtoken requests for different resource
if (!requestInfo.stateMatch && window.parent && window.parent.AuthenticationContext()) {
var statesInParentContext = window.parent.AuthenticationContext()._renewStates;
for (var i = 0; i < statesInParentContext.length; i++) {
if (statesInParentContext[i] === requestInfo.stateResponse) {
requestInfo.requestType = this.REQUEST_TYPE.RENEW_TOKEN;
requestInfo.stateMatch = true;
break;
}
}

@@ -631,560 +646,554 @@ }

}
}
return requestInfo;
};
return requestInfo;
};
AuthenticationContext.prototype._getResourceFromState = function (state) {
if (state) {
var splitIndex = state.indexOf('|');
if (splitIndex > -1 && splitIndex + 1 < state.length) {
return state.substring(splitIndex + 1);
AuthenticationContext.prototype._getResourceFromState = function (state) {
if (state) {
var splitIndex = state.indexOf('|');
if (splitIndex > -1 && splitIndex + 1 < state.length) {
return state.substring(splitIndex + 1);
}
}
}
return '';
};
return '';
};
/**
* Saves token from hash that is received from redirect.
* @param {string} hash - Hash passed from redirect page
* @returns {string} error message related to login
*/
AuthenticationContext.prototype.saveTokenFromHash = function (requestInfo) {
this.info('State status:' + requestInfo.stateMatch + '; Request type:' + requestInfo.requestType);
this._saveItem(this.CONSTANTS.STORAGE.ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, '');
/**
* Saves token from hash that is received from redirect.
* @param {string} hash - Hash passed from redirect page
* @returns {string} error message related to login
*/
AuthenticationContext.prototype.saveTokenFromHash = function (requestInfo) {
this.info('State status:' + requestInfo.stateMatch + '; Request type:' + requestInfo.requestType);
this._saveItem(this.CONSTANTS.STORAGE.ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, '');
// Record error
if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION)) {
this.info('Error :' + requestInfo.parameters.error + '; Error description:' + requestInfo.parameters[this.CONSTANTS.ERROR_DESCRIPTION]);
this._saveItem(this.CONSTANTS.STORAGE.ERROR, requestInfo.parameters.error);
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, requestInfo.parameters[this.CONSTANTS.ERROR_DESCRIPTION]);
var resource = this._getResourceFromState(requestInfo.stateResponse);
if (requestInfo.requestType === this.REQUEST_TYPE.LOGIN) {
this._loginInProgress = false;
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, requestInfo.parameters.errorDescription);
}
} else {
// Record error
if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION)) {
this.info('Error :' + requestInfo.parameters.error + '; Error description:' + requestInfo.parameters[this.CONSTANTS.ERROR_DESCRIPTION]);
this._saveItem(this.CONSTANTS.STORAGE.ERROR, requestInfo.parameters.error);
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, requestInfo.parameters[this.CONSTANTS.ERROR_DESCRIPTION]);
// It must verify the state from redirect
if (requestInfo.stateMatch) {
// record tokens to storage if exists
this.info('State is right');
if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.SESSION_STATE)) {
this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE, requestInfo.parameters[this.CONSTANTS.SESSION_STATE]);
if (requestInfo.requestType === this.REQUEST_TYPE.LOGIN) {
this._loginInProgress = false;
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, requestInfo.parameters.error_description);
}
} else {
// It must verify the state from redirect
if (requestInfo.stateMatch) {
// record tokens to storage if exists
this.info('State is right');
if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.SESSION_STATE)) {
this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE, requestInfo.parameters[this.CONSTANTS.SESSION_STATE]);
}
var keys, resource;
var keys;
if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN)) {
this.info('Fragment has access token');
resource = this._getResourceFromState(requestInfo.stateResponse);
if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN)) {
this.info('Fragment has access token');
if (!this._hasResource(resource)) {
keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS) || '';
this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, keys + resource + this.CONSTANTS.RESOURCE_DELIMETER);
if (!this._hasResource(resource)) {
keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS) || '';
this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, keys + resource + this.CONSTANTS.RESOURCE_DELIMETER);
}
// 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]));
}
// 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]));
}
if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)) {
this.info('Fragment has id token');
this._loginInProgress = false;
this._user = this._createUser(requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);
if (this._user && this._user.profile) {
if (this._user.profile.nonce !== this._getItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN)) {
this._user = null;
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, 'Nonce is not same as ' + this._idTokenNonce);
} else {
this._saveItem(this.CONSTANTS.STORAGE.IDTOKEN, requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);
if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)) {
this.info('Fragment has id token');
this._loginInProgress = false;
// Save idtoken as access token for app itself
resource = this.config.loginResource ? this.config.loginResource : this.config.clientId;
if (!this._hasResource(resource)) {
keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS) || '';
this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, keys + resource + this.CONSTANTS.RESOURCE_DELIMETER);
this._user = this._createUser(requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);
if (this._user && this._user.profile) {
if (this._user.profile.nonce !== this._getItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN)) {
this._user = null;
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, 'Nonce is not same as ' + this._idTokenNonce);
} 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;
if (!this._hasResource(resource)) {
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.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 + resource, requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);
this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, this._user.profile.exp);
}
else {
this._saveItem(this.CONSTANTS.STORAGE.ERROR, 'invalid id_token');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, 'Invalid id_token. id_token: ' + requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);
}
}
} else {
this._saveItem(this.CONSTANTS.STORAGE.ERROR, 'Invalid_state');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, 'Invalid_state. state: ' + requestInfo.stateResponse);
}
} else {
this._saveItem(this.CONSTANTS.STORAGE.ERROR, 'Invalid_state');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, 'Invalid_state. state: ' + requestInfo.stateResponse);
}
}
};
this._saveItem(this.CONSTANTS.STORAGE.RENEW_STATUS + resource, this.CONSTANTS.TOKEN_RENEW_STATUS_COMPLETED);
};
/**
* Gets resource for given endpoint if mapping is provided with config.
* @param {string} endpoint - API endoibt
* @returns {string} resource for this API endpoint
*/
AuthenticationContext.prototype.getResourceForEndpoint = function (endpoint) {
if (this.config && this.config.endpoints) {
for (var configEndpoint in this.config.endpoints) {
// configEndpoint is like /api/Todo requested endpoint can be /api/Todo/1
if (endpoint.indexOf(configEndpoint) > -1) {
return this.config.endpoints[configEndpoint];
/**
* Gets resource for given endpoint if mapping is provided with config.
* @param {string} endpoint - API endoibt
* @returns {string} resource for this API endpoint
*/
AuthenticationContext.prototype.getResourceForEndpoint = function (endpoint) {
if (this.config && this.config.endpoints) {
for (var configEndpoint in this.config.endpoints) {
// configEndpoint is like /api/Todo requested endpoint can be /api/Todo/1
if (endpoint.indexOf(configEndpoint) > -1) {
return this.config.endpoints[configEndpoint];
}
}
}
}
// default resource will be clientid if nothing specified
// App will use idtoken for calls to itself
// check if it's staring from http or https, needs to match with app host
if (endpoint.indexOf('http://') > -1 || endpoint.indexOf('https://') > -1) {
if (this._getHostFromUri(endpoint) === this._getHostFromUri(this.config.redirectUri)) {
return this.config.loginResource;
// default resource will be clientid if nothing specified
// App will use idtoken for calls to itself
// check if it's staring from http or https, needs to match with app host
if (endpoint.indexOf('http://') > -1 || endpoint.indexOf('https://') > -1) {
if (this._getHostFromUri(endpoint) === this._getHostFromUri(this.config.redirectUri)) {
return this.config.loginResource;
}
}
}
// in angular level, the url for $http interceptor call could be relative url,
// if it's relative call, we'll treat it as app backend call.
else {
// if user specified list of anonymous endpoints, no need to send token to these endpoints, return null.
if (this.config && this.config.anonymousEndpoints) {
for (var i = 0; i < this.config.anonymousEndpoints.length; i++) {
if (endpoint.indexOf(this.config.anonymousEndpoints[i]) > -1) {
return null;
// in angular level, the url for $http interceptor call could be relative url,
// if it's relative call, we'll treat it as app backend call.
else {
// if user specified list of anonymous endpoints, no need to send token to these endpoints, return null.
if (this.config && this.config.anonymousEndpoints) {
for (var i = 0; i < this.config.anonymousEndpoints.length; i++) {
if (endpoint.indexOf(this.config.anonymousEndpoints[i]) > -1) {
return null;
}
}
}
// all other app's backend calls are secured.
return this.config.loginResource;
}
// all other app's backend calls are secured.
return this.config.loginResource;
}
// if not the app's own backend or not a domain listed in the endpoints structure
return null;
};
// if not the app's own backend or not a domain listed in the endpoints structure
return null;
};
AuthenticationContext.prototype._getHostFromUri = function (uri) {
// remove http:// or https:// from uri
var extractedUri = String(uri).replace(/^(https?:)\/\//, '');
AuthenticationContext.prototype._getHostFromUri = function (uri) {
// remove http:// or https:// from uri
var extractedUri = String(uri).replace(/^(https?:)\/\//, '');
extractedUri = extractedUri.split('/')[0];
return extractedUri;
};
extractedUri = extractedUri.split('/')[0];
return extractedUri;
};
/*exported oauth2Callback */
AuthenticationContext.prototype.handleWindowCallback = function () {
// This is for regular javascript usage for redirect handling
// need to make sure this is for callback
var hash = window.location.hash;
if (this.isCallback(hash)) {
var requestInfo = this.getRequestInfo(hash);
this.info('Returned from redirect url');
this.saveTokenFromHash(requestInfo);
var callback = null;
if ((requestInfo.requestType === this.REQUEST_TYPE.RENEW_TOKEN && window.parent)) {
// iframe call but same single page
this.verbose('Window is in iframe');
callback = window.parent.callBackMappedToRenewStates[requestInfo.stateResponse];
window.src = '';
} else if (window && window.oauth2Callback) {
this.verbose('Window is redirecting');
callback = this.callback;
/*exported oauth2Callback */
AuthenticationContext.prototype.handleWindowCallback = function () {
// This is for regular javascript usage for redirect handling
// need to make sure this is for callback
var hash = window.location.hash;
if (this.isCallback(hash)) {
var requestInfo = this.getRequestInfo(hash);
this.info('Returned from redirect url');
this.saveTokenFromHash(requestInfo);
var callback = null;
if ((requestInfo.requestType === this.REQUEST_TYPE.RENEW_TOKEN) && window.parent && (window.parent !== window)) {
// iframe call but same single page
this.verbose('Window is in iframe');
callback = window.parent.callBackMappedToRenewStates[requestInfo.stateResponse];
if (callback)
callback(this._getItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters[this.CONSTANTS.ACCESS_TOKEN] || requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);
return;
} else if (window && window.oauth2Callback) {
this.verbose('Window is redirecting');
callback = this.callback;
}
window.location = this._getItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST);
}
};
window.location.hash = '';
window.location = this._getItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST);
if (requestInfo.requestType === this.REQUEST_TYPE.RENEW_TOKEN) {
callback(this._getItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters[this.CONSTANTS.ACCESS_TOKEN] || requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);
return;
AuthenticationContext.prototype._getNavigateUrl = function (responseType, resource) {
var tenant = 'common';
if (this.config.tenant) {
tenant = this.config.tenant;
}
}
};
AuthenticationContext.prototype._getNavigateUrl = function (responseType, resource) {
var tenant = 'common';
if (this.config.tenant) {
tenant = this.config.tenant;
}
var urlNavigate = this.instance + tenant + '/oauth2/authorize' + this._serialize(responseType, this.config, resource) + this._addLibMetadata();
this.info('Navigate url:' + urlNavigate);
return urlNavigate;
};
if (this.config.instance) {
this.instance = this.config.instance;
}
AuthenticationContext.prototype._extractIdToken = function (encodedIdToken) {
// id token will be decoded to get the username
var decodedToken = this._decodeJwt(encodedIdToken);
if (!decodedToken) {
return null;
}
var urlNavigate = this.instance + tenant + '/oauth2/authorize' + this._serialize(responseType, this.config, resource) + this._addLibMetadata();
this.info('Navigate url:' + urlNavigate);
return urlNavigate;
};
try {
var base64IdToken = decodedToken.JWSPayload;
var base64Decoded = this._base64DecodeStringUrlSafe(base64IdToken);
if (!base64Decoded) {
this.info('The returned id_token could not be base64 url safe decoded.');
return null;
}
AuthenticationContext.prototype._extractIdToken = function (encodedIdToken) {
// id token will be decoded to get the username
var decodedToken = this._decodeJwt(encodedIdToken);
if (!decodedToken) {
// ECMA script has JSON built-in support
return JSON.parse(base64Decoded);
} catch (err) {
this.error('The returned id_token could not be decoded', err);
}
return null;
}
};
try {
var base64IdToken = decodedToken.JWSPayload;
var base64Decoded = this._base64DecodeStringUrlSafe(base64IdToken);
if (!base64Decoded) {
this.info('The returned id_token could not be base64 url safe decoded.');
return null;
AuthenticationContext.prototype._base64DecodeStringUrlSafe = function (base64IdToken) {
// html5 should support atob function for decoding
base64IdToken = base64IdToken.replace(/-/g, '+').replace(/_/g, '/');
if (window.atob) {
return decodeURIComponent(escape(window.atob(base64IdToken))); // jshint ignore:line
}
else {
return decodeURIComponent(escape(this._decode(base64IdToken)));
}
};
// ECMA script has JSON built-in support
return JSON.parse(base64Decoded);
} catch (err) {
this.error('The returned id_token could not be decoded', err);
}
//Take https://cdnjs.cloudflare.com/ajax/libs/Base64/0.3.0/base64.js and https://en.wikipedia.org/wiki/Base64 as reference.
AuthenticationContext.prototype._decode = function (base64IdToken) {
var codes = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
base64IdToken = String(base64IdToken).replace(/=+$/, '');
return null;
};
AuthenticationContext.prototype._extractUserName = function (encodedIdToken) {
// id token will be decoded to get the username
try {
var parsed = this._extractIdToken(encodedIdToken);
if (parsed) {
if (parsed.hasOwnProperty('upn')) {
return parsed.upn;
} else if (parsed.hasOwnProperty('email')) {
return parsed.email;
}
var length = base64IdToken.length;
if (length % 4 === 1) {
throw new Error('The token to be decoded is not correctly encoded.');
}
} catch (err) {
this.error('The returned id_token could not be decoded', err);
}
return null;
};
var h1, h2, h3, h4, bits, c1, c2, c3, decoded = '';
for (var i = 0; i < length; i += 4) {
//Every 4 base64 encoded character will be converted to 3 byte string, which is 24 bits
// then 6 bits per base64 encoded character
h1 = codes.indexOf(base64IdToken.charAt(i));
h2 = codes.indexOf(base64IdToken.charAt(i + 1));
h3 = codes.indexOf(base64IdToken.charAt(i + 2));
h4 = codes.indexOf(base64IdToken.charAt(i + 3));
AuthenticationContext.prototype._base64DecodeStringUrlSafe = function (base64IdToken) {
// html5 should support atob function for decoding
base64IdToken = base64IdToken.replace(/-/g, '+').replace(/_/g, '/');
if (window.atob) {
return decodeURIComponent(escape(window.atob(base64IdToken))); // jshint ignore:line
}
else {
return decodeURIComponent(escape(this._decode(base64IdToken)));
}
};
// For padding, if last two are '='
if (i + 2 === length - 1) {
bits = h1 << 18 | h2 << 12 | h3 << 6;
c1 = bits >> 16 & 255;
c2 = bits >> 8 & 255;
decoded += String.fromCharCode(c1, c2);
break;
}
// if last one is '='
else if (i + 1 === length - 1) {
bits = h1 << 18 | h2 << 12
c1 = bits >> 16 & 255;
decoded += String.fromCharCode(c1);
break;
}
//Take https://cdnjs.cloudflare.com/ajax/libs/Base64/0.3.0/base64.js and https://en.wikipedia.org/wiki/Base64 as reference.
AuthenticationContext.prototype._decode = function (base64IdToken) {
var codes = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
base64IdToken = String(base64IdToken).replace(/=+$/, '');
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
var length = base64IdToken.length;
if (length % 4 === 1) {
throw new Error('The token to be decoded is not correctly encoded.');
}
var h1, h2, h3, h4, bits, c1, c2, c3, decoded = '';
for (var i = 0; i < length; i += 4) {
//Every 4 base64 encoded character will be converted to 3 byte string, which is 24 bits
// then 6 bits per base64 encoded character
h1 = codes.indexOf(base64IdToken.charAt(i));
h2 = codes.indexOf(base64IdToken.charAt(i + 1));
h3 = codes.indexOf(base64IdToken.charAt(i + 2));
h4 = codes.indexOf(base64IdToken.charAt(i + 3));
// For padding, if last two are '='
if (i + 2 === length - 1) {
bits = h1 << 18 | h2 << 12 | h3 << 6;
// then convert to 3 byte chars
c1 = bits >> 16 & 255;
c2 = bits >> 8 & 255;
decoded += String.fromCharCode(c1, c2);
break;
c3 = bits & 255;
decoded += String.fromCharCode(c1, c2, c3);
}
// if last one is '='
else if (i + 1 === length - 1) {
bits = h1 << 18 | h2 << 12
c1 = bits >> 16 & 255;
decoded += String.fromCharCode(c1);
break;
}
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
return decoded;
};
// then convert to 3 byte chars
c1 = bits >> 16 & 255;
c2 = bits >> 8 & 255;
c3 = bits & 255;
// Adal.node js crack function
AuthenticationContext.prototype._decodeJwt = function (jwtToken) {
if (this._isEmpty(jwtToken)) {
return null;
};
decoded += String.fromCharCode(c1, c2, c3);
}
var idTokenPartsRegex = /^([^\.\s]*)\.([^\.\s]+)\.([^\.\s]*)$/;
return decoded;
};
var matches = idTokenPartsRegex.exec(jwtToken);
if (!matches || matches.length < 4) {
this.warn('The returned id_token is not parseable.');
return null;
}
// Adal.node js crack function
AuthenticationContext.prototype._decodeJwt = function (jwtToken) {
if (this._isEmpty(jwtToken)) {
return null;
var crackedToken = {
header: matches[1],
JWSPayload: matches[2],
JWSSig: matches[3]
};
return crackedToken;
};
var idTokenPartsRegex = /^([^\.\s]*)\.([^\.\s]+)\.([^\.\s]*)$/;
AuthenticationContext.prototype._convertUrlSafeToRegularBase64EncodedString = function (str) {
return str.replace('-', '+').replace('_', '/');
};
var matches = idTokenPartsRegex.exec(jwtToken);
if (!matches || matches.length < 4) {
this.warn('The returned id_token is not parseable.');
return null;
}
AuthenticationContext.prototype._serialize = function (responseType, obj, resource) {
var str = [];
if (obj !== null) {
str.push('?response_type=' + responseType);
str.push('client_id=' + encodeURIComponent(obj.clientId));
if (resource) {
str.push('resource=' + encodeURIComponent(resource));
}
var crackedToken = {
header: matches[1],
JWSPayload: matches[2],
JWSSig: matches[3]
};
str.push('redirect_uri=' + encodeURIComponent(obj.redirectUri));
str.push('state=' + encodeURIComponent(obj.state));
return crackedToken;
};
if (obj.hasOwnProperty('slice')) {
str.push('slice=' + encodeURIComponent(obj.slice));
}
AuthenticationContext.prototype._convertUrlSafeToRegularBase64EncodedString = function (str) {
return str.replace('-', '+').replace('_', '/');
};
if (obj.hasOwnProperty('extraQueryParameter')) {
str.push(obj.extraQueryParameter);
}
AuthenticationContext.prototype._serialize = function (responseType, obj, resource) {
var str = [];
if (obj !== null) {
str.push('?response_type=' + responseType);
str.push('client_id=' + encodeURIComponent(obj.clientId));
if (resource) {
str.push('resource=' + encodeURIComponent(resource));
var correlationId = obj.correlationId ? obj.correlationId : this._guid();
str.push('client-request-id=' + encodeURIComponent(correlationId));
}
str.push('redirect_uri=' + encodeURIComponent(obj.redirectUri));
str.push('state=' + encodeURIComponent(obj.state));
return str.join('&');
};
if (obj.hasOwnProperty('slice')) {
str.push('slice=' + encodeURIComponent(obj.slice));
AuthenticationContext.prototype._deserialize = function (query) {
var match,
pl = /\+/g, // Regex for replacing addition symbol with a space
search = /([^&=]+)=([^&]*)/g,
decode = function (s) {
return decodeURIComponent(s.replace(pl, ' '));
},
obj = {};
match = search.exec(query);
while (match) {
obj[decode(match[1])] = decode(match[2]);
match = search.exec(query);
}
if (obj.hasOwnProperty('extraQueryParameter')) {
str.push(obj.extraQueryParameter);
}
return obj;
};
if (obj.correlationId) {
str.push('client-request-id=' + encodeURIComponent(obj.correlationId));
/* jshint ignore:start */
AuthenticationContext.prototype._guid = function () {
// RFC4122: The version 4 UUID is meant for generating UUIDs from truly-random or
// pseudo-random numbers.
// The algorithm is as follows:
// Set the two most significant bits (bits 6 and 7) of the
// clock_seq_hi_and_reserved to zero and one, respectively.
// Set the four most significant bits (bits 12 through 15) of the
// time_hi_and_version field to the 4-bit version number from
// Section 4.1.3. Version4
// Set all the other bits to randomly (or pseudo-randomly) chosen
// values.
// UUID = time-low "-" time-mid "-"time-high-and-version "-"clock-seq-reserved and low(2hexOctet)"-" node
// time-low = 4hexOctet
// time-mid = 2hexOctet
// time-high-and-version = 2hexOctet
// clock-seq-and-reserved = hexOctet:
// clock-seq-low = hexOctet
// node = 6hexOctet
// Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
// y could be 1000, 1001, 1010, 1011 since most significant two bits needs to be 10
// y values are 8, 9, A, B
var guidHolder = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
var hex = '0123456789abcdef';
var r = 0;
var guidResponse = "";
for (var i = 0; i < 36; i++) {
if (guidHolder[i] !== '-' && guidHolder[i] !== '4') {
// each x and y needs to be random
r = Math.random() * 16 | 0;
}
if (guidHolder[i] === 'x') {
guidResponse += hex[r];
} else if (guidHolder[i] === 'y') {
// clock-seq-and-reserved first hex is filtered and remaining hex values are random
r &= 0x3; // bit and with 0011 to set pos 2 to zero ?0??
r |= 0x8; // set pos 3 to 1 as 1???
guidResponse += hex[r];
} else {
guidResponse += guidHolder[i];
}
}
}
return str.join('&');
};
return guidResponse;
};
/* jshint ignore:end */
AuthenticationContext.prototype._deserialize = function (query) {
var match,
pl = /\+/g, // Regex for replacing addition symbol with a space
search = /([^&=]+)=?([^&]*)/g,
decode = function (s) {
return decodeURIComponent(s.replace(pl, ' '));
},
obj = {};
match = search.exec(query);
while (match) {
obj[decode(match[1])] = decode(match[2]);
match = search.exec(query);
}
AuthenticationContext.prototype._expiresIn = function (expires) {
return this._now() + parseInt(expires, 10);
};
return obj;
};
AuthenticationContext.prototype._now = function () {
return Math.round(new Date().getTime() / 1000.0);
};
/* jshint ignore:start */
AuthenticationContext.prototype._guid = function () {
// RFC4122: The version 4 UUID is meant for generating UUIDs from truly-random or
// pseudo-random numbers.
// The algorithm is as follows:
// Set the two most significant bits (bits 6 and 7) of the
// clock_seq_hi_and_reserved to zero and one, respectively.
// Set the four most significant bits (bits 12 through 15) of the
// time_hi_and_version field to the 4-bit version number from
// Section 4.1.3. Version4
// Set all the other bits to randomly (or pseudo-randomly) chosen
// values.
// UUID = time-low "-" time-mid "-"time-high-and-version "-"clock-seq-reserved and low(2hexOctet)"-" node
// time-low = 4hexOctet
// time-mid = 2hexOctet
// time-high-and-version = 2hexOctet
// clock-seq-and-reserved = hexOctet:
// clock-seq-low = hexOctet
// node = 6hexOctet
// Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
// y could be 1000, 1001, 1010, 1011 since most significant two bits needs to be 10
// y values are 8, 9, A, B
var guidHolder = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
var hex = '0123456789abcdef';
var r = 0;
var guidResponse = "";
for (var i = 0; i < 36; i++) {
if (guidHolder[i] !== '-' && guidHolder[i] !== '4') {
// each x and y needs to be random
r = Math.random() * 16 | 0;
}
if (guidHolder[i] === 'x') {
guidResponse += hex[r];
} else if (guidHolder[i] === 'y') {
// clock-seq-and-reserved first hex is filtered and remaining hex values are random
r &= 0x3; // bit and with 0011 to set pos 2 to zero ?0??
r |= 0x8; // set pos 3 to 1 as 1???
guidResponse += hex[r];
} else {
guidResponse += guidHolder[i];
AuthenticationContext.prototype._addAdalFrame = function (iframeId) {
if (typeof iframeId === 'undefined') {
return;
}
}
return guidResponse;
};
/* jshint ignore:end */
this.info('Add adal frame to document:' + iframeId);
var adalFrame = document.getElementById(iframeId);
AuthenticationContext.prototype._expiresIn = function (expires) {
return this._now() + parseInt(expires, 10);
};
if (!adalFrame) {
if (document.createElement && document.documentElement &&
(window.opera || window.navigator.userAgent.indexOf('MSIE 5.0') === -1)) {
var ifr = document.createElement('iframe');
ifr.setAttribute('id', iframeId);
ifr.style.visibility = 'hidden';
ifr.style.position = 'absolute';
ifr.style.width = ifr.style.height = ifr.borderWidth = '0px';
AuthenticationContext.prototype._now = function () {
return Math.round(new Date().getTime() / 1000.0);
};
adalFrame = document.getElementsByTagName('body')[0].appendChild(ifr);
}
else if (document.body && document.body.insertAdjacentHTML) {
document.body.insertAdjacentHTML('beforeEnd', '<iframe name="' + iframeId + '" id="' + iframeId + '" style="display:none"></iframe>');
}
if (window.frames && window.frames[iframeId]) {
adalFrame = window.frames[iframeId];
}
}
return adalFrame;
};
AuthenticationContext.prototype._addAdalFrame = function (iframeId) {
if (typeof iframeId === 'undefined') {
return;
}
AuthenticationContext.prototype._saveItem = function (key, obj) {
this.info('Add adal frame to document:' + iframeId);
var adalFrame = document.getElementById(iframeId);
if (this.config && this.config.cacheLocation && this.config.cacheLocation === 'localStorage') {
if (!adalFrame) {
if (document.createElement && document.documentElement &&
(window.opera || window.navigator.userAgent.indexOf('MSIE 5.0') === -1)) {
var ifr = document.createElement('iframe');
ifr.setAttribute('id', iframeId);
ifr.style.visibility = 'hidden';
ifr.style.position = 'absolute';
ifr.style.width = ifr.style.height = ifr.borderWidth = '0px';
if (!this._supportsLocalStorage()) {
this.info('Local storage is not supported');
return false;
}
adalFrame = document.getElementsByTagName('body')[0].appendChild(ifr);
localStorage.setItem(key, obj);
return true;
}
else if (document.body && document.body.insertAdjacentHTML) {
document.body.insertAdjacentHTML('beforeEnd', '<iframe name="' + iframeId + '" id="' + iframeId + '" style="display:none"></iframe>');
}
if (window.frames && window.frames[iframeId]) {
adalFrame = window.frames[iframeId];
}
}
return adalFrame;
};
AuthenticationContext.prototype._saveItem = function (key, obj) {
if (this.config && this.config.cacheLocation && this.config.cacheLocation === 'localStorage') {
if (!this._supportsLocalStorage()) {
this.info('Local storage is not supported');
// Default as session storage
if (!this._supportsSessionStorage()) {
this.info('Session storage is not supported');
return false;
}
localStorage.setItem(key, obj);
sessionStorage.setItem(key, obj);
return true;
}
};
// Default as session storage
if (!this._supportsSessionStorage()) {
this.info('Session storage is not supported');
return false;
}
AuthenticationContext.prototype._getItem = function (key) {
sessionStorage.setItem(key, obj);
return true;
};
if (this.config && this.config.cacheLocation && this.config.cacheLocation === 'localStorage') {
AuthenticationContext.prototype._getItem = function (key) {
if (!this._supportsLocalStorage()) {
this.info('Local storage is not supported');
return null;
}
if (this.config && this.config.cacheLocation && this.config.cacheLocation === 'localStorage') {
return localStorage.getItem(key);
}
if (!this._supportsLocalStorage()) {
this.info('Local storage is not supported');
// Default as session storage
if (!this._supportsSessionStorage()) {
this.info('Session storage is not supported');
return null;
}
return localStorage.getItem(key);
}
return sessionStorage.getItem(key);
};
// Default as session storage
if (!this._supportsSessionStorage()) {
this.info('Session storage is not supported');
return null;
}
AuthenticationContext.prototype._supportsLocalStorage = function () {
try {
return 'localStorage' in window && window['localStorage'];
} catch (e) {
return false;
}
};
return sessionStorage.getItem(key);
};
AuthenticationContext.prototype._supportsSessionStorage = function () {
try {
return 'sessionStorage' in window && window['sessionStorage'];
} catch (e) {
return false;
}
};
AuthenticationContext.prototype._supportsLocalStorage = function () {
try {
return 'localStorage' in window && window['localStorage'];
} catch (e) {
return false;
}
};
AuthenticationContext.prototype._cloneConfig = function (obj) {
if (null === obj || 'object' !== typeof obj) {
return obj;
}
AuthenticationContext.prototype._supportsSessionStorage = function () {
try {
return 'sessionStorage' in window && window['sessionStorage'];
} catch (e) {
return false;
}
};
var copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) {
copy[attr] = obj[attr];
}
}
return copy;
};
AuthenticationContext.prototype._cloneConfig = function (obj) {
if (null === obj || 'object' !== typeof obj) {
return obj;
}
AuthenticationContext.prototype._addLibMetadata = function () {
// x-client-SKU
// x-client-Ver
return '&x-client-SKU=Js&x-client-Ver=' + this._libVersion();
};
var copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) {
copy[attr] = obj[attr];
}
}
return copy;
};
AuthenticationContext.prototype.log = function (level, message, error) {
if (level <= Logging.level) {
var timestamp = new Date().toUTCString();
var formattedMessage = '';
AuthenticationContext.prototype._addLibMetadata = function () {
// x-client-SKU
// x-client-Ver
return '&x-client-SKU=Js&x-client-Ver=' + this._libVersion();
};
if (this.config.correlationId)
formattedMessage = timestamp + ':' + this.config.correlationId + '-' + this._libVersion() + '-' + this.CONSTANTS.LEVEL_STRING_MAP[level] + ' ' + message;
else
formattedMessage = timestamp + ':' + this._libVersion() + '-' + this.CONSTANTS.LEVEL_STRING_MAP[level] + ' ' + message;
AuthenticationContext.prototype.log = function (level, message, error) {
if (level <= Logging.level) {
var correlationId = this.config.correlationId;
var timestamp = new Date().toUTCString();
if (error) {
formattedMessage += '\nstack:\n' + error.stack;
}
var formattedMessage = timestamp + ':' + correlationId + '-' + this._libVersion() + '-' + this.CONSTANTS.LEVEL_STRING_MAP[level] + ' ' + message;
if (error) {
formattedMessage += '\nstack:\n' + error.stack;
Logging.log(formattedMessage);
}
};
Logging.log(formattedMessage);
}
};
AuthenticationContext.prototype.error = function (message, error) {
this.log(this.CONSTANTS.LOGGING_LEVEL.ERROR, message, error);
};
AuthenticationContext.prototype.error = function (message, error) {
this.log(this.CONSTANTS.LOGGING_LEVEL.ERROR, message, error);
};
AuthenticationContext.prototype.warn = function (message) {
this.log(this.CONSTANTS.LOGGING_LEVEL.WARN, message, null);
};
AuthenticationContext.prototype.warn = function (message) {
this.log(this.CONSTANTS.LOGGING_LEVEL.WARN, message, null);
};
AuthenticationContext.prototype.info = function (message) {
this.log(this.CONSTANTS.LOGGING_LEVEL.INFO, message, null);
};
AuthenticationContext.prototype.info = function (message) {
this.log(this.CONSTANTS.LOGGING_LEVEL.INFO, message, null);
};
AuthenticationContext.prototype.verbose = function (message) {
this.log(this.CONSTANTS.LOGGING_LEVEL.VERBOSE, message, null);
};
AuthenticationContext.prototype.verbose = function (message) {
this.log(this.CONSTANTS.LOGGING_LEVEL.VERBOSE, message, null);
};
AuthenticationContext.prototype._libVersion = function () {
return '1.0.11';
};
AuthenticationContext.prototype._libVersion = function () {
return '1.0.10';
};
if (typeof module !== 'undefined' && module.exports) {
module.exports = AuthenticationContext;
module.exports.inject = function (conf) {
return new AuthenticationContext(conf);
};
}
return AuthenticationContext;
}());

@@ -13,3 +13,3 @@ {

},
"version": "1.0.10",
"version": "1.0.11",
"description": "Windows Azure Active Directory Client Library for js",

@@ -16,0 +16,0 @@ "keywords": [

@@ -8,5 +8,19 @@ Active Directory Authentication Library (ADAL) for JavaScript

## 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. We also provide full walkthroughs for authentication flows such as OAuth2, OpenID Connect, Graph API, and other awesome features.
## Community Help and Support
We leverage [Stack Overflow](http://stackoverflow.com/) to work with the community on supporting Azure Active Directory and its SDKs, including this one! We highly recommend you ask your questions on Stack Overflow (we're all on there!) Also browser existing issues to see if someone has had your question before.
We recommend you use the "adal" tag so we can see it! Here is the latest Q&A on Stack Overflow for ADAL: [http://stackoverflow.com/questions/tagged/adal](http://stackoverflow.com/questions/tagged/adal)
## Security Reporting
If you find a security issue with our libraries or services please report it to [secure@microsoft.com](mailto:secure@microsoft.com) with as much detail as possible. Your submission may be eligible for a bounty through the [Microsoft Bounty](http://aka.ms/bugbounty) program. Please do not post security issues to GitHub Issues or any other public site. We will contact you shortly upon receiving the information. We encourage you to get notifications of when security incidents occur by visiting [this page](https://technet.microsoft.com/en-us/security/dd252948) and subscribing to Security Advisory Alerts.
## The Library
This is a GA released version. The current version is **1.0.10**.
This is a GA released version. The current version is **1.0.11**.

@@ -22,6 +36,6 @@ You have multiple ways of getting ADAL JS:

<!-- Latest compiled and minified JavaScript -->
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.10/js/adal.min.js"></script>
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.10/js/adal-angular.min.js"></script>
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.11/js/adal.min.js"></script>
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.11/js/adal-angular.min.js"></script>
CDN will be updated to latest version 1.0.10.
CDN will be updated to latest version 1.0.11.

@@ -268,1 +282,4 @@ Via Bower:

## We Value and Adhere to the Microsoft Open Source Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

@@ -24,5 +24,5 @@ //----------------------------------------------------------------------

'use strict';
describe('TaskCtl', function () {
var scope, $httpBackend, adalServiceProvider, rootScope, controller, q, window;
var scope, $httpBackend, adalServiceProvider, rootScope, controller, q, window, route, location;

@@ -32,4 +32,4 @@ //mock Application to allow us to inject our own dependencies

//mock the controller for the same reason and include $rootScope and $controller
beforeEach(angular.mock.inject(function (_adalAuthenticationService_, _$rootScope_, _$controller_, _$httpBackend_, _$q_, _$window_) {
//mock the controller for the same reason and include $scope and $controller
beforeEach(angular.mock.inject(function (_adalAuthenticationService_, _$rootScope_, _$controller_, _$httpBackend_, _$q_, _$window_, _$route_, _$location_) {
adalServiceProvider = _adalAuthenticationService_;

@@ -41,7 +41,8 @@ rootScope = _$rootScope_;

window = _$window_;
route = _$route_;
location = _$location_;
//create an empty scope
scope = rootScope.$new();
adalServiceProvider.userInfo = { userName: 'UserVerify', isAuthenticated: true };
adalServiceProvider.getCachedToken = function (resource) {

@@ -58,3 +59,3 @@ console.log('Requesting token for resource:' + resource);

if (resource === adalServiceProvider.config.loginResource) {
return 'Token456';
return 'Token456';
}

@@ -86,4 +87,4 @@

it('assigns user', function () {
expect(scope.user.userName).toBe('UserVerify');
expect(scope.user.isAuthenticated).toBe(true);
expect(scope.user.userName).toBe('');
expect(scope.user.isAuthenticated).toBe(false);
});

@@ -123,7 +124,7 @@

it('does not send tokens for webapi(https) call not in endpoints list', function () {
$httpBackend.expectGET('https://test.com/', function (headers) {
return headers.hasOwnProperty('Authorization') === false;
}).respond(200);
scope.taskCall2();
$httpBackend.flush();
$httpBackend.expectGET('https://test.com/', function (headers) {
return headers.hasOwnProperty('Authorization') === false;
}).respond(200);
scope.taskCall2();
$httpBackend.flush();
});

@@ -136,6 +137,6 @@

scope.taskCall6();
$httpBackend.flush();
$httpBackend.flush();
});
it ('send tokens for app backend call not in endpoints list', function () {
it('send tokens for app backend call not in endpoints list', function () {
$httpBackend.expectGET('/someapi/item', function (headers) {

@@ -209,9 +210,9 @@ return headers.Authorization === 'Bearer Token456'

rootScope.$on('adal:errorResponse', function (event, message) {
scope.$on('adal:errorResponse', function (event, message) {
expect(event.name).toBe('adal:errorResponse');
expect(message).toBe('login in progress, cancelling the request');
expect(message.data).toBe('login in progress, cancelling the request for https://myapp.com/someapi/item');
});
scope.taskCall5();
rootScope.$apply();
expect(rootScope.$broadcast).toHaveBeenCalledWith('adal:errorResponse', 'login in progress, cancelling the request');
scope.$apply();
expect(rootScope.$broadcast).toHaveBeenCalled();
});

@@ -223,3 +224,3 @@

callback: function () { },
_renewStates: { }
_renewStates: {}
};

@@ -229,7 +230,7 @@ };

spyOn(rootScope, '$broadcast').andCallThrough();
rootScope.$on('adal:stateMismatch', function (event, message) {
scope.$on('adal:stateMismatch', function (event, message) {
expect(event.name).toBe('adal:stateMismatch');
expect(message).toBe('Invalid_state. state: 4343');
});
rootScope.$apply();
scope.$apply();
expect(rootScope.$broadcast).toHaveBeenCalled();

@@ -242,3 +243,3 @@ });

callback: function () { },
_renewStates: [ '4343' ]
_renewStates: ['4343']
};

@@ -251,4 +252,160 @@ };

window.location.hash = 'error=sample&error_description=renewfailed&state=4343';
rootScope.$apply();
scope.$apply();
});
it('tests callback is called when response contains access token', function () {
window.parent.AuthenticationContext = function () {
return {
callback: function () { },
_renewStates: ['4343']
};
};
window.parent.callBackMappedToRenewStates = {};
window.parent.callBackMappedToRenewStates['4343'] = function (error, token) {
expect(error).toBe('');
expect(token).toBe('newAccessToken123');
};
window.location.hash = 'access_token=newAccessToken123&state=4343';
scope.$apply();
});
it('tests callback is called when response contains id token', function () {
window.parent.AuthenticationContext = function () {
return {
callback: function () { },
_renewStates: ['4343']
};
};
window.parent.callBackMappedToRenewStates = {};
window.parent.callBackMappedToRenewStates['4343'] = function (error, token) {
expect(error).toBe('Invalid id_token. id_token: newIdToken123');
expect(token).toBe('newIdToken123');
};
window.location.hash = 'id_token=newIdToken123&state=4343';
scope.$apply();
});
it('tests login failure after users logs in', function () {
window.parent.AuthenticationContext = function () {
return {
callback: 'callback',
_renewStates: ['1234']
};
};
window.parent.callBackMappedToRenewStates = {};
window.parent.callBackMappedToRenewStates['1234'] = 'callback';
var mockInvalidClientIdToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJjbGllbnQxMjMiLCJuYW1lIjoiSm9obiBEb2UiLCJ1cG4iOiJqb2huQGVtYWlsLmNvbSJ9.zNX4vfLzlbFeKHZ9BMN3sYLtEEE-0o1RoL4NUhXz-l8';
window.location.hash = 'id_token=' + mockInvalidClientIdToken + '&state=1234';
spyOn(rootScope, '$broadcast').andCallThrough();
scope.$on('adal:loginFailure', function (event, message) {
expect(event.name).toBe('adal:loginFailure');
expect(message).toBe('Invalid id_token. id_token: ' + mockInvalidClientIdToken);
});
scope.$apply();
expect(rootScope.$broadcast).toHaveBeenCalled();
});
it('tests login success after users logs in', function () {
window.parent.AuthenticationContext = function () {
return {
callback: 'callback',
_renewStates: ['1234']
};
};
window.parent.callBackMappedToRenewStates = {};
window.parent.callBackMappedToRenewStates['1234'] = 'callback';
var mockIdToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJjbGllbnRpZDEyMyIsIm5hbWUiOiJKb2huIERvZSIsInVwbiI6ImpvaG5AZW1haWwuY29tIiwibm9uY2UiOm51bGx9.DLCO6yIWhnNBYfHH8qFPswcH4M2Alpjn6AZy7K6HENY';
window.location.hash = 'id_token=' + mockIdToken + '&state=1234';
spyOn(rootScope, '$broadcast').andCallThrough();
scope.$on('adal:loginSuccess', function (event, message) {
expect(event.name).toBe('adal:loginSuccess');
expect(adalServiceProvider.userInfo.userName).toBe('john@email.com');
expect(adalServiceProvider.userInfo.profile.upn).toBe('john@email.com');
expect(adalServiceProvider.userInfo.profile.aud).toBe('clientid123');
});
scope.$apply();
expect(rootScope.$broadcast).toHaveBeenCalled();
});
it('tests auto id token renew when id token expires', function () {
window.parent.AuthenticationContext = function () {
return {
callback: 'callback',
_renewStates: ['1234']
};
};
window.parent.callBackMappedToRenewStates = {};
window.parent.callBackMappedToRenewStates['1234'] = 'callback';
var loginResourceOldValue = adalServiceProvider.config.loginResource;
adalServiceProvider.config.loginResource = null;
window.location.hash = 'hash';
spyOn(rootScope, '$broadcast').andCallThrough();
scope.$on('adal:loginFailure', function (event, message) {
expect(event.name).toBe('adal:loginFailure');
expect(message).toBe('auto renew failure');
});
scope.$apply();
adalServiceProvider.config.loginResource = loginResourceOldValue;
expect(rootScope.$broadcast).toHaveBeenCalled();
});
it('tests login handler', function () {
spyOn(rootScope, '$broadcast').andCallThrough();
adalServiceProvider.config.localLoginUrl = 'localLoginUrl';
adalServiceProvider.login();
scope.$on('$locationChangeStart', function (event, newUrl, oldUrl) {
expect(newUrl).toContain('localLoginUrl');
console.log('location event called');
event.preventDefault();
})
expect(adalServiceProvider.loginInProgress()).toBe(false);
scope.$apply();
expect(rootScope.$broadcast).toHaveBeenCalled();
adalServiceProvider.config.localLoginUrl = null
adalServiceProvider.login();
scope.$on('adal:loginRedirect', function (event, message) {
expect(event.name).toBe('adal:loginRedirect');
});
expect(adalServiceProvider.loginInProgress()).toBe(true);
expect(rootScope.$broadcast).toHaveBeenCalled();
});
it('tests route change handler', function () {
var todoRoute = route.routes['/todoList'];
var homeRoute = route.routes['/home'];
var aboutRoute = route.routes['/about'];
location.url('/todoList');
scope.$apply();
expect(route.current.controller).toBe(todoRoute.controller);
expect(route.current.template).toBe(todoRoute.template);
location.url('/home');
scope.$apply();
expect(route.current.controller).toBe(homeRoute.controller);
expect(route.current.template).toBe(homeRoute.template);
$httpBackend.expectGET('about.html').respond(200);
location.url('/about');
scope.$apply();
expect(route.current.controller).toBe(aboutRoute.controller);
expect(route.current.templateUrl).toBe(aboutRoute.templateUrl);
expect(adalServiceProvider.config.anonymousEndpoints).toContain(aboutRoute.templateUrl);
$httpBackend.flush();
});
it('checks if Logging is defined', function () {
Logging.level = 2;
Logging.log = function (message) {
window.logMessage = message;
}
adalServiceProvider.info("test message");
expect(window.logMessage).toContain("test message");
expect(Logging.level).toEqual(2);
});
});

@@ -26,5 +26,13 @@ //----------------------------------------------------------------------

$routeProvider.
when('/home', {
controller: 'homeController',
template: '<div>home</div>'
}).
when('/about', {
controller: 'aboutController',
templateUrl: 'about.html'
}).
when('/todoList', {
controller: 'todoListController',
templateUrl: '/App/Views/todoList.html',
template: '<div>todoList</div>',
requireADLogin: true

@@ -31,0 +39,0 @@ }).

@@ -24,2 +24,3 @@ //----------------------------------------------------------------------

var confighash = { hash: '#' };
global.window = {};
var AdalModule = require('../../../lib/adal.js');

@@ -29,2 +30,3 @@

var adal;
global.Logging = global.window.Logging;
var window = {

@@ -49,13 +51,16 @@ location: {

};
var frameMock = {
src: 'start'
};
var mockFrames = {};
var documentMock = {
getElementById: function () {
return frameMock;
getElementById: function (frameId) {
if (!mockFrames[frameId]) {
mockFrames[frameId] = { src: 'start' };
}
return mockFrames[frameId];
}
};
var angularMock = {};
var conf = { loginResource: 'default resource', tenant: 'testtenant', clientId: 'e9a5a8b6-8af7-4719-9821-0deef255f68e' };
var conf = { loginResource: 'defaultResource', tenant: 'testtenant', clientId: 'e9a5a8b6-8af7-4719-9821-0deef255f68e' };
var testPage = 'this is a song';

@@ -70,2 +75,6 @@ var STORAGE_PREFIX = 'adal';

var IDTOKEN_MOCK = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjVUa0d0S1JrZ2FpZXpFWTJFc0xDMmdPTGpBNCJ9.eyJhdWQiOiJlOWE1YThiNi04YWY3LTQ3MTktOTgyMS0wZGVlZjI1NWY2OGUiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLXBwZS5uZXQvNTJkNGIwNzItOTQ3MC00OWZiLTg3MjEtYmMzYTFjOTkxMmExLyIsImlhdCI6MTQxMTk1OTAwMCwibmJmIjoxNDExOTU5MDAwLCJleHAiOjE0MTE5NjI5MDAsInZlciI6IjEuMCIsInRpZCI6IjUyZDRiMDcyLTk0NzAtNDlmYi04NzIxLWJjM2ExYzk5MTJhMSIsImFtciI6WyJwd2QiXSwib2lkIjoiZmEzYzVmYTctN2Q5OC00Zjk3LWJmYzQtZGJkM2E0YTAyNDMxIiwidXBuIjoidXNlckBvYXV0aGltcGxpY2l0LmNjc2N0cC5uZXQiLCJ1bmlxdWVfbmFtZSI6InVzZXJAb2F1dGhpbXBsaWNpdC5jY3NjdHAubmV0Iiwic3ViIjoiWTdUbXhFY09IUzI0NGFHa3RjbWpicnNrdk5tU1I4WHo5XzZmbVc2NXloZyIsImZhbWlseV9uYW1lIjoiYSIsImdpdmVuX25hbWUiOiJ1c2VyIiwibm9uY2UiOiI4MGZmYTkwYS1jYjc0LTRkMGYtYTRhYy1hZTFmOTNlMzJmZTAiLCJwd2RfZXhwIjoiNTc3OTkxMCIsInB3ZF91cmwiOiJodHRwczovL3BvcnRhbC5taWNyb3NvZnRvbmxpbmUuY29tL0NoYW5nZVBhc3N3b3JkLmFzcHgifQ.WHsl8TH1rQ3dQbRkV0TS6GBVAxzNOpG3nGG6mpEBCwAOCbyW6qRsSoo4qq8I5IGyerDf2cvcS-zzatHEROpRC9dcpwkRm6ta5dFZuouFyZ_QiYVKSMwfzEC_FI-6p7eT8gY6FbV51bp-Ah_WKJqEmaXv-lqjIpgsMGeWDgZRlB9cPODXosBq-PEk0q27Be-_A-KefQacJuWTX2eEhECLyuAu-ETVJb7s19jQrs_LJXz_ISib4DdTKPa7XTBDJlVGdCI18ctB67XwGmGi8MevkeKqFI8dkykTxeJ0MXMmEQbE6Fw-gxmP7uJYbZ61Jqwsw24zMDMeXatk2VWMBPCuhA';
var STATE = '585bd348-4d52-4689-b9c7-d8480564f368';
var SESSION_STATE = '451c6916-27cf-4eae-81cd-accf96126398';
var VALID_URLFRAGMENT = 'id_token=' + IDTOKEN_MOCK + '' + '&state=' + STATE + '&session_state=' + SESSION_STATE;
var INVALID_URLFRAGMENT = 'id_token' + IDTOKEN_MOCK + '' + '&state=' + STATE + '&session_state=' + SESSION_STATE;
var storageFake = function () {

@@ -79,3 +88,3 @@ var store = {};

if (typeof value != 'undefined') {
store[key] = value + '';
store[key] = value;
}

@@ -107,2 +116,3 @@ },

// Init adal
global.window = window;

@@ -119,4 +129,5 @@ global.localStorage = storageFake;

adal._activeRenewals = {};
adal.CONSTANTS.LOADFRAME_TIMEOUT = 800;
});
it('gets specific resource for defined endpoint mapping', function () {

@@ -130,4 +141,4 @@ adal.config.endpoints = { 'a': 'resource for a' };

adal.config.endpoints = null;
expect(adal.getResourceForEndpoint('a')).toBe('default resource');
expect(adal.getResourceForEndpoint('b')).toBe('default resource');
expect(adal.getResourceForEndpoint('a')).toBe('defaultResource');
expect(adal.getResourceForEndpoint('b')).toBe('defaultResource');
});

@@ -140,3 +151,3 @@

expect(adal.getResourceForEndpoint('default/app/views/abc')).toBe(null);
expect(adal.getResourceForEndpoint('app/home')).toBe('default resource');
expect(adal.getResourceForEndpoint('app/home')).toBe('defaultResource');
});

@@ -166,3 +177,2 @@

spyOn(adal, 'promptUser');
console.log('instance:' + adal.instance);
adal.login();

@@ -195,6 +205,6 @@ expect(adal.promptUser).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=id_token&client_id=client&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333'

adal.login();
expect(adal.config.displayCall).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=id_token&client_id=client&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333'
expect(adal.config.displayCall).toHaveBeenCalledWith(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=id_token&client_id=client&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333'
+ '&client-request-id=33333333-3333-4333-b333-333333333333'
+ adal._addLibMetadata()
+ '&nonce=33333333-3333-4333-b333-333333333333'
+ '&nonce=33333333-3333-4333-b333-333333333333'
);

@@ -239,3 +249,3 @@ expect(adal.config.state).toBe('33333333-3333-4333-b333-333333333333');

adal._renewStates = [];
adal._user = { userName: 'test@testuser.com' };
adal._user = { profile: { 'upn': 'test@testuser.com' }, userName: 'test@domain.com'};
adal.acquireToken(RESOURCE1, callback);

@@ -247,12 +257,13 @@ expect(adal.callback).toBe(callback);

console.log('Waiting for initial timeout');
waits(2000);
waitsFor(function () {
return mockFrames['adalRenewFrame' + RESOURCE1].src !== 'about:blank';
}, 'iframe src not updated', 2000);
runs(function () {
console.log('Frame src:' + frameMock.src);
expect(frameMock.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'
+ '&client-request-id=33333333-3333-4333-b333-333333333333' + adal._addLibMetadata() + '&prompt=none&login_hint=test%40testuser.com&domain_hint=testuser.com&nonce=33333333-3333-4333-b333-333333333333');
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'
+ '&client-request-id=33333333-3333-4333-b333-333333333333' + adal._addLibMetadata() + '&prompt=none&login_hint=test%40testuser.com&domain_hint=testuser.com');
});
});
//Necessary for integration with Angular when multiple http calls are queued.

@@ -271,9 +282,9 @@ it('allows multiple callers to be notified when the token is renewed', function () {

};
var callback2 = function(valErr, valToken){
var callback2 = function (valErr, valToken) {
err2 = valErr;
token2 = valToken;
};
adal._renewStates = [];
adal._user = { userName: 'test@testuser.com' };
adal._user = { profile: { 'upn': 'test@testuser.com' }, userName: 'test@domain.com' };
adal.acquireToken(RESOURCE1, callback);

@@ -286,10 +297,11 @@ //Simulate second acquire i.e. second service call from Angular.

console.log('Waiting for initial timeout');
waits(2000);
waitsFor(function () {
return mockFrames['adalRenewFrame' + RESOURCE1].src !== 'about:blank';
}, 'iframe src not updated', 2000);
runs(function () {
console.log('Frame src:' + frameMock.src);
expect(frameMock.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'
+ '&client-request-id=33333333-3333-4333-b333-333333333333' + adal._addLibMetadata() + '&prompt=none&login_hint=test%40testuser.com&domain_hint=testuser.com&nonce=33333333-3333-4333-b333-333333333333');
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'
+ '&client-request-id=33333333-3333-4333-b333-333333333333' + adal._addLibMetadata() + '&prompt=none&login_hint=test%40testuser.com&domain_hint=testuser.com');
});
//Simulate callback from the frame.

@@ -301,3 +313,3 @@ //adal.callback(null, '33333333-3333-4333-b333-333333333333');

expect(token2).toBe('33333333-3333-4333-b333-333333333333', 'Second callback should be called');
});

@@ -323,3 +335,3 @@

expect(adal._guid()).toBe('ffffffff-ffff-4fff-bfff-ffffffffffff');
mathMock.random = function () {

@@ -355,3 +367,2 @@ return 0.9;

storageFake.setItem(adal.CONSTANTS.STORAGE.STATE_LOGIN, 'state login');
storageFake.setItem(adal.CONSTANTS.STORAGE.START_PAGE, 'start page');
storageFake.setItem(adal.CONSTANTS.STORAGE.USERNAME, 'username');

@@ -513,3 +524,3 @@ storageFake.setItem(adal.CONSTANTS.STORAGE.ERROR, 'error');

adal.saveTokenFromHash(requestInfo);
expect(storageFake.getItem(adal.CONSTANTS.STORAGE.EXPIRATION_KEY + 'loginResource1')).toBe(mathMock.round(1) + 3589 + '');
expect(storageFake.getItem(adal.CONSTANTS.STORAGE.EXPIRATION_KEY + 'loginResource1')).toBe(mathMock.round(1) + 3589);
});

@@ -527,3 +538,3 @@

requestType: adal.REQUEST_TYPE.ID_TOKEN
};
};
storageFake.setItem(adal.CONSTANTS.STORAGE.NONCE_IDTOKEN, '19e67b24-cd99-45b6-a588-840e3f8f2a70');

@@ -536,3 +547,2 @@ adal.config.clientId = conf.clientId;

expect(cachedUser.profile.upn).toBe('user@oauthimplicit.ccsctp.net');
console.log('test extract idtoken done');
});

@@ -592,18 +602,18 @@

it ('test decode with no padding', function () {
it('test decode with no padding', function () {
expect(adal._decode('ZGVjb2RlIHRlc3Rz')).toBe('decode tests');
});
it ('test decode with one = padding', function () {
expect(adal._decode('ZWNvZGUgdGVzdHM=')).toBe('ecode tests');
it('test decode with one = padding', function () {
expect(adal._decode('ZWNvZGUgdGVzdHM=')).toBe('ecode tests');
});
it ('test decode with two == padding', function () {
expect(adal._decode('Y29kZSB0ZXN0cw==')).toBe('code tests');
it('test decode with two == padding', function () {
expect(adal._decode('Y29kZSB0ZXN0cw==')).toBe('code tests');
})
it ('test decode throw error', function () {
try{
adal._decode('YW55I');
} catch(e) {
it('test decode throw error', function () {
try {
adal._decode('YW55I');
} catch (e) {
expect(e.message).toBe('The token to be decoded is not correctly encoded.');

@@ -613,3 +623,3 @@ }

it ('test get resource for endpoint from app backend', function () {
it('test get resource for endpoint from app backend', function () {
adal.config.redirectUri = 'https://host.com/page';

@@ -623,3 +633,3 @@ expect(adal.getResourceForEndpoint('https://host.com')).toBe(adal.config.loginResource);

it ('test host extraction', function () {
it('test host extraction', function () {
expect(adal._getHostFromUri('https://a.com/b/c')).toBe('a.com');

@@ -651,5 +661,222 @@ expect(adal._getHostFromUri('http://a.com')).toBe('a.com');

it('checks if Logging is defined on window', function () {
Logging.level = 2;
Logging.log = function (message) {
window.logMessage = message;
}
adal.promptUser();
expect(window.logMessage).toContain("Navigate url is empty");
expect(Logging.level).toEqual(2);
});
it('tests the load frame timeout method', function () {
adal._loadFrameTimeout('urlnavigation', 'frameName', RESOURCE1);
expect(storageFake.getItem(adal.CONSTANTS.STORAGE.RENEW_STATUS + RESOURCE1)).toBe(adal.CONSTANTS.TOKEN_RENEW_STATUS_IN_PROGRESS);
// timeout interval passed
waitsFor(function () {
return storageFake.getItem(adal.CONSTANTS.STORAGE.RENEW_STATUS + RESOURCE1) === adal.CONSTANTS.TOKEN_RENEW_STATUS_CANCELED;
}, 'token renew status not updated', 1000);
runs(function () {
expect(storageFake.getItem(adal.CONSTANTS.STORAGE.RENEW_STATUS + RESOURCE1)).toBe(adal.CONSTANTS.TOKEN_RENEW_STATUS_CANCELED);
adal._loadFrameTimeout('urlnavigation', 'frameName', RESOURCE1);
expect(storageFake.getItem(adal.CONSTANTS.STORAGE.RENEW_STATUS + RESOURCE1)).toBe(adal.CONSTANTS.TOKEN_RENEW_STATUS_IN_PROGRESS);
var requestInfo = {
valid: true,
parameters: { 'access_token': 'token123', 'state': '123', 'expires_in': '23' },
stateMatch: true,
stateResponse: '64532|' + RESOURCE1,
requestType: adal.REQUEST_TYPE.RENEW_TOKEN
};
adal.saveTokenFromHash(requestInfo);
expect(storageFake.getItem(adal.CONSTANTS.STORAGE.RENEW_STATUS + RESOURCE1)).toBe(adal.CONSTANTS.TOKEN_RENEW_STATUS_COMPLETED);
});
});
it('tests that callbacks are called when renewal token request was canceled', function () {
adal.config.expireOffsetSeconds = SECONDS_TO_EXPIRE + 100;
var err = '';
var token = '';
var callback = function (valErr, valToken) {
err = valErr;
token = valToken;
};
adal._renewStates = [];
adal._user = { userName: 'test@testuser.com' };
adal.acquireToken(RESOURCE1, callback);
waitsFor(function () {
return storageFake.getItem(adal.CONSTANTS.STORAGE.RENEW_STATUS + RESOURCE1) === adal.CONSTANTS.TOKEN_RENEW_STATUS_CANCELED;
}, 'token renew status not updated', 1000);
runs(function () {
expect(storageFake.getItem(adal.CONSTANTS.STORAGE.RENEW_STATUS + RESOURCE1)).toBe(adal.CONSTANTS.TOKEN_RENEW_STATUS_CANCELED);
expect(err).toBe('Token renewal operation failed due to timeout');
expect(token).toBe(null);
});
});
it('attempts to renewidToken if token expired and renew is allowed', function () {
adal.config.redirectUri = 'contoso_site';
adal.config.clientId = 'client';
adal.config.expireOffsetSeconds = SECONDS_TO_EXPIRE + 100;
adal.config.tenant = 'testtenant';
var err = '';
var token = '';
var callback = function (valErr, valToken) {
err = valErr;
token = valToken;
};
adal._renewStates = [];
adal._user = { profile: { 'upn': 'test@testuser.com' }, userName: 'test@domain.com' };
adal.acquireToken(adal.config.clientId, callback);
expect(storageFake.getItem(adal.CONSTANTS.STORAGE.NONCE_IDTOKEN)).toBe('33333333-3333-4333-b333-333333333333');
expect(adal.config.state).toBe('33333333-3333-4333-b333-333333333333' + '|' + 'client');
expect(adal._renewStates.length).toBe(1);
expect(storageFake.getItem(adal.CONSTANTS.STORAGE.LOGIN_REQUEST)).toBe('');
// Wait for initial timeout load
console.log('Waiting for initial timeout');
waitsFor(function () {
return mockFrames['adalIdTokenFrame'].src !== 'about:blank';
}, 'iframe src not updated', 2000);
runs(function () {
expect(mockFrames['adalIdTokenFrame'].src).toBe(DEFAULT_INSTANCE + conf.tenant + '/oauth2/authorize?response_type=id_token&client_id=' + adal.config.clientId + '&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333%7Cclient'
+ '&client-request-id=33333333-3333-4333-b333-333333333333' + adal._addLibMetadata() + '&prompt=none&login_hint=test%40testuser.com&domain_hint=testuser.com' + '&nonce=33333333-3333-4333-b333-333333333333');
});
});
it('tests handleWindowCallback function for RENEW_TOKEN', function () {
window.location.hash = '#/id_token=' + IDTOKEN_MOCK;
adal.getRequestInfo = function (hash) {
return {
valid: true,
parameters: { 'error_description': 'error description', 'error': 'invalid', 'id_token': IDTOKEN_MOCK, 'session_state': '61ae5247-eaf8-4496-a667-32b0acbad7a0', 'state': '19537a2a-e9e7-489d-ae7d-3eefab9e4137' },
stateMatch: true,
stateResponse: '19537a2a-e9e7-489d-ae7d-3eefab9e4137',
requestType: adal.REQUEST_TYPE.RENEW_TOKEN
};
};
var err = '';
var token = '';
var callback = function (valErr, valToken) {
err = valErr;
token = valToken;
};
window.parent = {};
window.parent.callBackMappedToRenewStates = {};
window.parent.callBackMappedToRenewStates[adal.getRequestInfo().stateResponse] = callback;
adal.handleWindowCallback();
expect(err).toBe('error description');
expect(token).toBe(IDTOKEN_MOCK);
});
it('tests handleWindowCallback function for LOGIN_REQUEST', function () {
window.location = {};
window.location.hash = '#/id_token=' + IDTOKEN_MOCK;
adal.getRequestInfo = function () {
return {
valid: true,
parameters: { 'error_description': 'error description', 'error': 'invalid', 'id_token': IDTOKEN_MOCK, 'session_state': '61ae5247-eaf8-4496-a667-32b0acbad7a0', 'state': '19537a2a-e9e7-489d-ae7d-3eefab9e4137' },
stateMatch: true,
stateResponse: '19537a2a-e9e7-489d-ae7d-3eefab9e4137',
requestType: adal.REQUEST_TYPE.LOGIN_REQUEST
};
};
storageFake.setItem(adal.CONSTANTS.STORAGE.LOGIN_REQUEST, "www.test.com");
window.oauth2Callback = {};
adal.handleWindowCallback();
expect(window.location).toBe('www.test.com');
});
it('use the same correlationId for each request sent to AAD if set by user', function () {
adal.config.correlationId = '33333333-3333-4333-b333-333333333333';
adal.config.redirectUri = 'contoso_site';
adal.config.clientId = 'client';
adal.config.expireOffsetSeconds = SECONDS_TO_EXPIRE + 100;
var callback = function () {
};
adal._renewStates = [];
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'
+ '&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'
+ '&client-request-id=33333333-3333-4333-b333-333333333333' + adal._addLibMetadata() + '&prompt=none', 'adalRenewFrametoken.resource1', 'token.resource1');
});
it('generates new correlationId for each request sent to AAD if not set by user', function () {
adal.config.correlationId = null;
adal.config.redirectUri = 'contoso_site';
adal.config.clientId = 'client';
adal.config.expireOffsetSeconds = SECONDS_TO_EXPIRE + 100;
var callback = function () {
};
adal._renewStates = [];
adal._user = { profile: { 'upn': 'test@testuser.com' }, userName: 'test@domain.com' };
mathMock.random = function () {
return 0.1;
};
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'
+ '&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 () {
return 0.3;
};
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'
+ '&client-request-id=44444444-4444-4444-8444-444444444444' + adal._addLibMetadata() + '&prompt=none', 'adalRenewFrametoken.resource1', 'token.resource1');
});
it('checks the deserialize method for extracting idToken', function () {
var obj = adal._deserialize(VALID_URLFRAGMENT);
expect(obj.id_token).toBe(IDTOKEN_MOCK);
expect(obj.state).toBe(STATE);
expect(obj.session_state).toBe(SESSION_STATE);
obj = adal._deserialize(INVALID_URLFRAGMENT);
expect(obj.id_token).toBeUndefined;
expect(obj.state).toBe(STATE);
expect(obj.session_state).toBe(SESSION_STATE);
expect(obj['id_token' + IDTOKEN_MOCK]).toBeUndefined;
var deserialize = adal._deserialize;//save initial state of function
adal._deserialize = function (query) {
var match,
pl = /\+/g, // Regex for replacing addition symbol with a space
search = /([^&=]+)=?([^&]*)/g,
decode = function (s) {
return decodeURIComponent(s.replace(pl, ' '));
},
obj = {};
match = search.exec(query);
while (match) {
obj[decode(match[1])] = decode(match[2]);
match = search.exec(query);
}
return obj;
}
obj = adal._deserialize(INVALID_URLFRAGMENT);
expect(obj['id_token' + IDTOKEN_MOCK]).toBe('');//This additional property is parsed because of ? operator in regex
expect(obj.id_token).toBeUndefined;
expect(obj.state).toBe(STATE);
expect(obj.session_state).toBe(SESSION_STATE);
adal._deserialize = deserialize;//reassign state to original function
});
// TODO angular intercepptor
// TODO angular authenticaitonService
});
// TODO angular authenticationService
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc