Skip to content
Open
115 changes: 80 additions & 35 deletions app/scripts/directives/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,27 @@ directives.directive('oauth', [
restrict: 'AE',
replace: true,
scope: {
site: '@', // (required) set the oauth server host (e.g. http://oauth.example.com)
clientId: '@', // (required) client id
redirectUri: '@', // (required) client redirect uri
responseType: '@', // (optional) response type, defaults to token (use 'token' for implicit flow and 'code' for authorization code flow
scope: '@', // (optional) scope
profileUri: '@', // (optional) user profile uri (e.g http://example.com/me)
template: '@', // (optional) template to render (e.g views/templates/default.html)
text: '@', // (optional) login text
authorizePath: '@', // (optional) authorization url
state: '@', // (optional) An arbitrary unique string created by your app to guard against Cross-site Request Forgery
storage: '@', // (optional) Store token in 'sessionStorage' or 'localStorage', defaults to 'sessionStorage'
nonce: '@', // (optional) Send nonce on auth request
// OpenID Connect extras, more details in id-token.js:
issuer: '@', // (optional for OpenID Connect) issuer of the id_token, should match the 'iss' claim in id_token payload
subject: '@', // (optional for OpenID Connect) subject of the id_token, should match the 'sub' claim in id_token payload
pubKey: '@', // (optional for OpenID Connect) the public key(RSA public key or X509 certificate in PEM format) to verify the signature
wellKnown: '@', // (optional for OpenID Connect) whether to load public key according to .well-known/openid-configuration endpoint
logoutPath: '@', // (optional) A url to go to at logout
sessionPath: '@' // (optional) A url to use to check the validity of the current token.
site: '@', // (required) set the oauth server host (e.g. http://oauth.example.com)
clientId: '@', // (required) client id
redirectUri: '@', // (required) client redirect uri
responseType: '@', // (optional) response type, defaults to token (use 'token' for implicit flow, 'code' for authorization code flow and 'password' for resource owner password
scope: '@', // (optional) scope
profileUri: '@', // (optional) user profile uri (e.g http://example.com/me)
template: '@', // (optional) template to render (e.g views/templates/default.html)
text: '@', // (optional) login text
authorizePath: '@', // (optional) authorization url
tokenPath: '@', // (optional) token url
state: '@', // (optional) An arbitrary unique string created by your app to guard against Cross-site Request Forgery
storage: '@', // (optional) Store token in 'sessionStorage' or 'localStorage', defaults to 'sessionStorage'
nonce: '@', // (optional) Send nonce on auth request
// OpenID Connect extras, more details in id-token.js:
issuer: '@', // (optional for OpenID Connect) issuer of the id_token, should match the 'iss' claim in id_token payload
subject: '@', // (optional for OpenID Connect) subject of the id_token, should match the 'sub' claim in id_token payload
pubKey: '@', // (optional for OpenID Connect) the public key(RSA public key or X509 certificate in PEM format) to verify the signature
wellKnown: '@', // (optional for OpenID Connect) whether to load public key according to .well-known/openid-configuration endpoint
logoutPath: '@', // (optional) A url to go to at logout
sessionPath: '@', // (optional) A url to use to check the validity of the current token.
disableCheckSession:'@' // (optional) can current token be checked ?
}
};

Expand All @@ -58,22 +60,29 @@ directives.directive('oauth', [
OidcConfig.load(scope) // loads OIDC configuration from .well-known/openid-configuration if necessary
.then(function() {
IdToken.set(scope);
AccessToken.set(scope); // sets the access token object (if existing, from fragment or session)
initProfile(scope); // gets the profile resource (if existing the access token)
initView(); // sets the view (logged in or out)
checkValidity(); // ensure the validity of the current token
AccessToken.set(scope).then(function () { // sets the access token object (if existing, from fragment or session)
})
["finally"](function () {
initProfile(scope); // gets the profile resource (if existing the access token)
initView(); // sets the view (logged in or out)
checkValidity(); // ensure the validity of the current token
});
});
};

var initAttributes = function() {
scope.authorizePath = scope.authorizePath || '/oauth/authorize';
scope.tokenPath = scope.tokenPath || '/oauth/token';
scope.template = scope.template || 'views/templates/default.html';
scope.responseType = scope.responseType || 'token';
scope.text = scope.text || 'Sign In';
scope.state = scope.state || undefined;
scope.scope = scope.scope || undefined;
scope.storage = scope.storage || 'sessionStorage';
scope.authorizePath = scope.authorizePath || '/oauth/authorize';
scope.tokenPath = scope.tokenPath || '/oauth/token';
scope.template = scope.template || 'views/templates/default.html';
scope.responseType = scope.responseType || 'token';
scope.text = scope.text || 'Sign In';
scope.state = scope.state || undefined;
scope.scope = scope.scope || undefined;
scope.storage = scope.storage || 'sessionStorage';
scope.disableCheckSession = scope.disableCheckSession || false;
scope.typedLogin = "";
scope.typedPassword = "";
scope.typedKeepConnection = false;
};

var compile = function() {
Expand All @@ -96,8 +105,8 @@ directives.directive('oauth', [
var initView = function () {
var token = AccessToken.get();

if (!token) {
return scope.login();
if (!token && scope.responseType !== "password") {
return expired();
} // without access token it's logged out, so we attempt to log in
if (AccessToken.expired()) {
return expired();
Expand All @@ -115,12 +124,43 @@ directives.directive('oauth', [
};

scope.logout = function () {
scope.typedLogin = "";
scope.typedPassword = "";
scope.typedKeepConnection = false;
Endpoint.logout();
$rootScope.$broadcast('oauth:loggedOut');
scope.show = 'logged-out';
AccessToken.destroy();
};

scope.checkPassword = function () {
$http({
method: "POST",
url: scope.site + scope.tokenPath,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: {grant_type: "password", username: scope.typedLogin, password: scope.typedPassword, scope: scope.scope}
}).then(function (result) {
if (scope.typedKeepConnection) {
AccessToken.setTokenFromPassword(scope, result.data, scope.typedLogin, scope.typedPassword, scope.scope);
} else {
AccessToken.setTokenFromPassword(scope, result.data);
scope.typedLogin = "";
scope.typedPassword = "";
scope.typedKeepConnection = false;
}
scope.show = "logged-in";
}, function () {
$rootScope.$broadcast('oauth:denied');
});
};

scope.$on('oauth:expired',expired);
scope.$on('oauth:expired', expired);

// user is authorized
var authorized = function() {
Expand All @@ -129,9 +169,13 @@ directives.directive('oauth', [
};

var expired = function() {
$rootScope.$broadcast('oauth:expired');
scope.show = 'logged-out';
scope.logout();
};

scope.runExpired = function() {
expired();
};

// set the oauth directive to the denied status
var denied = function() {
Expand Down Expand Up @@ -165,6 +209,7 @@ directives.directive('oauth', [
scope.$on('$stateChangeSuccess', function () {
$timeout(refreshDirective);
});

};

return definition;
Expand Down
Loading