Skip to content
This repository has been archived by the owner on Jun 26, 2021. It is now read-only.

Commit

Permalink
Merge pull request #114 from AzureAD/dev
Browse files Browse the repository at this point in the history
release to master
  • Loading branch information
omercs committed Apr 30, 2015
2 parents 0b0e8ff + 61e8113 commit 693c288
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 42 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Active Directory Authentication Library (ADAL) for JavaScript
Active Directory Authentication Library (ADAL) for JavaScript
====================================
[![Build Status](https://travis-ci.org/AzureAD/azure-activedirectory-library-for-js.svg?branch=master)](https://travis-ci.org/AzureAD/azure-activedirectory-library-for-js)

Expand Down Expand Up @@ -196,6 +196,8 @@ adalAuthenticationServiceProvider.init(

### Security
Tokens are accessible from javascript since Adal.JS is using HTML5 storage. Default storage option is sessionStorage, which keeps the tokens per session. You should ask user to login again for important operations on your app.
You should protect your site for XSS. Please check the article here: https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet


### CORS API usage and IE
Adal will get access token for given CORS API endpoints in the config. Access token is requested using Iframe. Iframe needs to access the cookies for the same domain that you did the initial sign in. IE does not allow to access cookies in IFrame for localhost. Your url needs to be fully qualified domain i.e http://yoursite.azurewebsites.com. Chrome does not have this restriction.
Expand All @@ -220,11 +222,12 @@ app.factory('contactService', ['$http', function ($http) {
```

You can read extended blogs for CORS API related to learn about Office365 usage.
Andrews related to Cors and office365 usage
Andrew's related to Cors and office365 usage
http://www.andrewconnell.com/blog/adal-js-cors-with-o365-apis-files-sharepoint
Vittorios blog
Vittorio's blog
http://www.cloudidentity.com/blog/2015/02/19/introducing-adal-js-v1/
http://www.cloudidentity.com/blog/2014/10/28/adal-javascript-and-angularjs-deep-dive/

### Trusted Site settings in IE
If you put your site in the trusted site list, cookies are not accessible for iFrame requests. You need to remove protected mode for Internet zone or add the authority url for the login to the trusted sites as well.

2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "adal-angular",
"version": "1.0.0",
"version": "1.0.1",
"homepage": "https://github.com/AzureAD/azure-activedirectory-library-for-js",
"authors": [
"MSOpentech"
Expand Down
57 changes: 32 additions & 25 deletions lib/adal-angular.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//----------------------------------------------------------------------
// AdalJS v1.0.0
// AdalJS v1.0.1
// @preserve Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
// Apache License 2.0
Expand Down Expand Up @@ -81,13 +81,18 @@ if (typeof module !== 'undefined' && module.exports) {

var locationChangeHandler = function () {
var hash = $window.location.hash;

if (_adal.isCallback(hash)) {
// callback can come from login or iframe request

var requestInfo = _adal.getRequestInfo(hash);
_adal.saveTokenFromHash(requestInfo);
$window.location.hash = '';

if ($location.$$html5) {
$window.location = $window.location.origin + $window.location.pathname;
} else {
$window.location.hash = '';
}

if (requestInfo.requestType !== _adal.REQUEST_TYPE.LOGIN) {
_adal.callback = $window.parent.AuthenticationContext().callback;
Expand Down Expand Up @@ -153,35 +158,37 @@ if (typeof module !== 'undefined' && module.exports) {
}, 1);
};

var loginHandler = function () {
_adal._logstatus('Login event for:' + $location.$$path);
if (_adal.config && _adal.config.localLoginUrl) {
$location.path(_adal.config.localLoginUrl);
} else {
// directly start login flow
_adal._saveItem(_adal.CONSTANTS.STORAGE.START_PAGE, $location.$$path);
_adal._logstatus('Start login at:' + window.location.href);
$rootScope.$broadcast('adal:loginRedirect');
_adal.login();
}
};

function isADLoginRequired(route, global) {
return global.requireADLogin ? route.requireADLogin !== false : !!route.requireADLogin;
}

var routeChangeHandler = function (e, nextRoute) {
if (nextRoute && nextRoute.$$route && nextRoute.$$route.requireADLogin) {
if (nextRoute && nextRoute.$$route && isADLoginRequired(nextRoute.$$route, _adal.config)) {
if (!_oauthData.isAuthenticated) {
console.log('Route change event for:' + $location.$$path);
if (_adal.config && _adal.config.localLoginUrl) {
$location.path(_adal.config.localLoginUrl);
} else {
// directly start login flow
_adal._saveItem(_adal.CONSTANTS.STORAGE.START_PAGE, $location.$$path);
console.log('Start login at:' + window.location.href);
$rootScope.$broadcast('adal:loginRedirect');
_adal.login();
}
_adal._logstatus('Route change event for:' + $location.$$path);
loginHandler();
}
}
};

var stateChangeHandler = function (e, nextRoute) {
if (nextRoute && nextRoute.requireADLogin) {
if (nextRoute && isADLoginRequired(nextRoute, _adal.config)) {
if (!_oauthData.isAuthenticated) {
console.log('Route change event for:' + nextRoute.url);
if (_adal.config && _adal.config.localLoginUrl) {
$location.path(_adal.config.localLoginUrl);
} else {
_adal._saveItem(_adal.CONSTANTS.STORAGE.START_PAGE, nextRoute.url);
console.log('Start login at:' + window.location.href);
$rootScope.$broadcast('adal:loginRedirect');
_adal.login();
}
_adal._logstatus('State change event for:' + $location.$$path);
loginHandler();
}
}
};
Expand Down Expand Up @@ -315,6 +322,6 @@ if (typeof module !== 'undefined' && module.exports) {
};
}]);
} else {
console.log('Angular.JS is not included');
console.error('Angular.JS is not included');
}
}());
14 changes: 7 additions & 7 deletions lib/adal.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//----------------------------------------------------------------------
// AdalJS v1.0.0
// AdalJS v1.0.1
// @preserve Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
// Apache License 2.0
Expand Down Expand Up @@ -40,7 +40,7 @@ if (typeof module !== 'undefined' && module.exports) {
* @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.windows.net/)
* @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
*/

Expand Down Expand Up @@ -110,7 +110,7 @@ AuthenticationContext = function (config) {
AuthenticationContext.prototype._singletonInstance = this;

// public
this.instance = 'https://login.windows.net/';
this.instance = 'https://login.microsoftonline.com/';
this.config = {};
this.callback = null;
this.popUp = false;
Expand Down Expand Up @@ -729,18 +729,18 @@ AuthenticationContext.prototype.handleWindowCallback = function () {
requestInfo.requestType === this.REQUEST_TYPE.ID_TOKEN) &&
window.parent) {
// iframe call but same single page
console.log('Window is in iframe');
this._logstatus('Window is in iframe');
callback = window.parent.AuthenticationContext().callback;
window.src = '';
} else if (window && window.oauth2Callback) {
console.log('Window is redirecting');
this._logstatus('Window is redirecting');
callback = this.callback;
}

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]);
callback(this._getItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters[this.CONSTANTS.ACCESS_TOKEN] || || requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);
return;
} else if (requestInfo.requestType === this.REQUEST_TYPE.ID_TOKEN) {
// JS context may not have the user if callback page was different, so parse idtoken again to callback
Expand All @@ -761,7 +761,7 @@ AuthenticationContext.prototype._getNavigateUrl = function (responseType, resour
}

var urlNavigate = this.instance + tenant + '/oauth2/authorize' + this._serialize(responseType, this.config, resource) + this._addClientId();
console.log('Navigate url:' + urlNavigate);
this._logstatus('Navigate url:' + urlNavigate);
return urlNavigate;
};

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"type": "git",
"url": ""
},
"version": "1.0.0",
"version": "1.0.1",
"description": "Windows Azure Active Directory Client Library for js",
"keywords": [
"implicit",
Expand Down
11 changes: 6 additions & 5 deletions tests/unit/spec/AdalSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ describe('Adal', function () {
var STORAGE_TOKEN_KEYS = STORAGE_PREFIX + '.token.keys';
var RESOURCE1 = 'token.resource1';
var SECONDS_TO_EXPIRE = 3600;
var DEFAULT_INSTANCE = "https://login.microsoftonline.com/";
var IDTOKEN_MOCK = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjVUa0d0S1JrZ2FpZXpFWTJFc0xDMmdPTGpBNCJ9.eyJhdWQiOiJlOWE1YThiNi04YWY3LTQ3MTktOTgyMS0wZGVlZjI1NWY2OGUiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLXBwZS5uZXQvNTJkNGIwNzItOTQ3MC00OWZiLTg3MjEtYmMzYTFjOTkxMmExLyIsImlhdCI6MTQxMTk1OTAwMCwibmJmIjoxNDExOTU5MDAwLCJleHAiOjE0MTE5NjI5MDAsInZlciI6IjEuMCIsInRpZCI6IjUyZDRiMDcyLTk0NzAtNDlmYi04NzIxLWJjM2ExYzk5MTJhMSIsImFtciI6WyJwd2QiXSwib2lkIjoiZmEzYzVmYTctN2Q5OC00Zjk3LWJmYzQtZGJkM2E0YTAyNDMxIiwidXBuIjoidXNlckBvYXV0aGltcGxpY2l0LmNjc2N0cC5uZXQiLCJ1bmlxdWVfbmFtZSI6InVzZXJAb2F1dGhpbXBsaWNpdC5jY3NjdHAubmV0Iiwic3ViIjoiWTdUbXhFY09IUzI0NGFHa3RjbWpicnNrdk5tU1I4WHo5XzZmbVc2NXloZyIsImZhbWlseV9uYW1lIjoiYSIsImdpdmVuX25hbWUiOiJ1c2VyIiwibm9uY2UiOiI4MGZmYTkwYS1jYjc0LTRkMGYtYTRhYy1hZTFmOTNlMzJmZTAiLCJwd2RfZXhwIjoiNTc3OTkxMCIsInB3ZF91cmwiOiJodHRwczovL3BvcnRhbC5taWNyb3NvZnRvbmxpbmUuY29tL0NoYW5nZVBhc3N3b3JkLmFzcHgifQ.WHsl8TH1rQ3dQbRkV0TS6GBVAxzNOpG3nGG6mpEBCwAOCbyW6qRsSoo4qq8I5IGyerDf2cvcS-zzatHEROpRC9dcpwkRm6ta5dFZuouFyZ_QiYVKSMwfzEC_FI-6p7eT8gY6FbV51bp-Ah_WKJqEmaXv-lqjIpgsMGeWDgZRlB9cPODXosBq-PEk0q27Be-_A-KefQacJuWTX2eEhECLyuAu-ETVJb7s19jQrs_LJXz_ISib4DdTKPa7XTBDJlVGdCI18ctB67XwGmGi8MevkeKqFI8dkykTxeJ0MXMmEQbE6Fw-gxmP7uJYbZ61Jqwsw24zMDMeXatk2VWMBPCuhA';
var storageFake = function () {
var store = {};
Expand Down Expand Up @@ -143,7 +144,7 @@ describe('Adal', function () {
spyOn(adal, 'promptUser');
console.log('instance:' + adal.instance);
adal.login();
expect(adal.promptUser).toHaveBeenCalledWith('https://login.windows.net/' + conf.tenant + '/oauth2/authorize?response_type=id_token&client_id=client&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333'
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._addClientId() + '&nonce=33333333-3333-4333-b333-333333333333');
expect(adal.config.state).toBe('33333333-3333-4333-b333-333333333333');
});
Expand All @@ -169,7 +170,7 @@ describe('Adal', function () {
adal.config.displayCall = displayCallback;
spyOn(adal.config, 'displayCall');
adal.login();
expect(adal.config.displayCall).toHaveBeenCalledWith('https://login.windows.net/' + 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'
+ adal._addClientId()
+ '&nonce=33333333-3333-4333-b333-333333333333'
);
Expand Down Expand Up @@ -236,7 +237,7 @@ describe('Adal', function () {

runs(function () {
console.log('Frame src:' + frameMock.src);
expect(frameMock.src).toBe('https://login.windows.net/' + conf.tenant + '/oauth2/authorize?response_type=token&client_id=client&resource=' + RESOURCE1 + '&redirect_uri=contoso_site&state=33333333-3333-4333-b333-333333333333%7Ctoken.resource1'
expect(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'
+ adal._addClientId() + '&prompt=none&login_hint=test%40testuser.com&domain_hint=testuser.com&nonce=33333333-3333-4333-b333-333333333333');
});

Expand Down Expand Up @@ -344,7 +345,7 @@ describe('Adal', function () {
adal.config.postLogoutRedirectUri = 'https://contoso.com/logout';
spyOn(adal, 'promptUser');
adal.logOut();
expect(adal.promptUser).toHaveBeenCalledWith('https://login.windows.net/' + adal.config.tenant + '/oauth2/logout?post_logout_redirect_uri=https%3A%2F%2Fcontoso.com%2Flogout');
expect(adal.promptUser).toHaveBeenCalledWith(DEFAULT_INSTANCE + adal.config.tenant + '/oauth2/logout?post_logout_redirect_uri=https%3A%2F%2Fcontoso.com%2Flogout');
});

it('uses common for tenant if not given at logout redirect', function () {
Expand All @@ -355,7 +356,7 @@ describe('Adal', function () {
adal.config.postLogoutRedirectUri = 'https://contoso.com/logout';
spyOn(adal, 'promptUser');
adal.logOut();
expect(adal.promptUser).toHaveBeenCalledWith('https://login.windows.net/common/oauth2/logout?post_logout_redirect_uri=https%3A%2F%2Fcontoso.com%2Flogout');
expect(adal.promptUser).toHaveBeenCalledWith(DEFAULT_INSTANCE + 'common/oauth2/logout?post_logout_redirect_uri=https%3A%2F%2Fcontoso.com%2Flogout');
});

it('gets user from cache', function () {
Expand Down

0 comments on commit 693c288

Please sign in to comment.