UNPKG

@acaprojects/a2-composer

Version:
604 lines 24.9 kB
import { Location } from '@angular/common'; import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; import { COMPOSER } from '../../settings'; import { DataStoreService } from '../data-store.service'; var OAuthService = (function () { function OAuthService(location, store) { this.location = location; this.store = store; this.clientId = ''; this.redirectUri = ''; this.loginUrl = ''; this.loginRedirect = ''; this.scope = ''; this.rngUrl = ''; this.oidc = false; this.state = ''; this.issuer = ''; this.logoutUrl = ''; this.refreshUri = ''; this.login_local = false; this.simple = false; this.debug = false; this._storage = 'local'; this.run_flow = false; this.needs_login = false; this.access_token_promise = null; this.refresh_token_promise = null; this.valid_access_token_promise = null; this.valid_id_token_promise = null; this.auth_header_promise = null; this.login_obs = new Subject(); } OAuthService.prototype.setStorage = function (storage) { this._storage = storage; }; Object.defineProperty(OAuthService.prototype, "login_url", { get: function () { return this.createLoginUrl('').then(function (url) { return url; }); }, enumerable: true, configurable: true }); Object.defineProperty(OAuthService.prototype, "refresh_url", { get: function () { return this.createRefreshUrl('').then(function (url) { return url; }, function (err) { return ''; }); }, enumerable: true, configurable: true }); OAuthService.prototype.needsLogin = function () { var _this = this; setTimeout(function () { _this.login_obs.next(_this.needs_login); }, 200); return this.login_obs; }; OAuthService.prototype.tryLogin = function (options) { var _this = this; return new Promise(function (resolve, reject) { _this.attemptLogin(options, resolve, reject); }); }; OAuthService.prototype.tryLoginWithIFrame = function () { throw new Error('tryLoginWithIFrame has not been implemented so far'); }; OAuthService.prototype.tryRefresh = function (timeoutInMsec) { throw new Error('tryRefresh has not been implemented so far'); }; OAuthService.prototype.getIdentityClaims = function () { var claims = this.store[this._storage].getItem(this.clientId + "_id_token_claims_obj") .then(function (res) { return res; }); if (!claims) { return null; } return JSON.parse(claims); }; OAuthService.prototype.getIdToken = function () { return this.store[this._storage].getItem(this.clientId + "_id_token").then(function (res) { return res; }); }; OAuthService.prototype.getAccessToken = function () { var _this = this; if (!this.access_token_promise) { this.access_token_promise = new Promise(function (resolve) { _this.store[_this._storage].getItem(_this.clientId + "_access_token").then(function (token) { if (!token) { _this.store[_this._storage].getItem("accessToken").then(function (token_local) { resolve(token_local); _this.access_token_promise = null; }); } else { resolve(token); _this.access_token_promise = null; } }); }); } return this.access_token_promise; }; OAuthService.prototype.getRefreshToken = function () { var _this = this; if (!this.refresh_token_promise) { this.refresh_token_promise = new Promise(function (resolve) { _this.store[_this._storage].getItem(_this.clientId + "_refresh_token").then(function (token) { if (!token) { _this.store[_this._storage].getItem("refreshToken").then(function (token_local) { resolve(token_local); _this.refresh_token_promise = null; }); } else { resolve(token); _this.refresh_token_promise = null; } }); }); } return this.refresh_token_promise; }; OAuthService.prototype.hasValidAccessToken = function () { var _this = this; if (!this.valid_access_token_promise) { this.valid_access_token_promise = new Promise(function (resolve, reject) { _this.getAccessToken().then(function (token) { _this.store[_this._storage].getItem(_this.clientId + "_expires_at").then(function (expiresAt) { setTimeout(function () { _this.valid_access_token_promise = null; }, 10); if (!expiresAt) { _this.store[_this._storage].getItem("accessExpiry").then(function (expiresAt_local) { var now = new Date(); if (!expiresAt || parseInt(expiresAt_local, 10) < now.getTime()) { return resolve(false); } return resolve(true); }); } else { var now = new Date(); if (expiresAt && parseInt(expiresAt, 10) < now.getTime()) { return resolve(false); } return resolve(true); } }); }); }); } return this.valid_access_token_promise; }; OAuthService.prototype.hasValidIdToken = function () { var _this = this; if (!this.valid_id_token_promise) { this.valid_id_token_promise = new Promise(function (resolve, reject) { if (_this.getIdToken) { _this.store[_this._storage].getItem(_this.clientId + "_id_token_expires_at") .then(function (expiresAt) { var now = new Date(); if (expiresAt && parseInt(expiresAt, 10) < now.getTime()) { return resolve(false); } else { return resolve(true); } }); } else { resolve(false); } }); } }; OAuthService.prototype.authorizationHeader = function () { var _this = this; if (!this.auth_header_promise) { this.auth_header_promise = new Promise(function (resolve) { _this.getAccessToken().then(function (token) { resolve("Bearer " + token); setTimeout(function () { _this.auth_header_promise = null; }, 1000); }); }); } return this.auth_header_promise; }; OAuthService.prototype.logOut = function () { var _this = this; COMPOSER.log('OAUTH', 'Logging out. Clear access tokens...'); var id_token = this.getIdToken(); this.clearAuth(); if (!this.logoutUrl) { setTimeout(function () { _this.location.replaceState(_this.location.path(), ''); }, 100); return; } var logoutUrl = this.logoutUrl.replace(/\{\{id_token\}\}/, id_token); COMPOSER.log('OAUTH', 'Redirecting to logout URL...'); location.href = logoutUrl; }; OAuthService.prototype.clearAuth = function () { var _this = this; COMPOSER.log('OAUTH', "Clearing authentication variables..."); var items = [ 'access_token', 'refresh_token', 'accesstoken', 'refreshtoken', 'id_token', 'idtoken', 'nonce', 'expires', 'expiry', 'login', 'oauth', ]; this.store[this._storage].keys().then(function (keys) { for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) { var key = keys_1[_i]; var lkey = key.toLowerCase(); for (var _a = 0, items_1 = items; _a < items_1.length; _a++) { var i = items_1[_a]; if (lkey.indexOf(i) >= 0) { _this.store[_this._storage].removeItem(key); COMPOSER.log('OAUTH', "Remove key '" + key + "' from " + _this._storage + " storage"); break; } } } }); }; OAuthService.prototype.createLoginUrl = function (state) { var _this = this; var that = this; if (typeof state === 'undefined') { state = ''; } return this.createAndSaveNonce().then(function (nonce) { if (state) { state = nonce + ';' + state; } else { state = nonce; } var response_type = _this.response_type ? _this.response_type : 'token'; if (_this.oidc) { response_type = 'id_token+' + response_type; } var url = _this.loginUrl + (_this.loginUrl.indexOf('?') < 0 ? '?' : '&') + 'response_type=' + encodeURIComponent(response_type) + '&client_id=' + encodeURIComponent(_this.clientId) + '&state=' + encodeURIComponent(state) + '&redirect_uri=' + encodeURIComponent(_this.redirectUri) + '&scope=' + encodeURIComponent(_this.scope); if (_this.oidc) { url += '&nonce=' + encodeURIComponent(nonce); } return url; }); }; OAuthService.prototype.createRefreshUrl = function (state) { var _this = this; if (typeof state === 'undefined') { state = ''; } return this.createAndSaveNonce().then(function (nonce) { var url = _this.refreshUri + '?client_id=' + encodeURIComponent(_this.clientId) + '&redirect_uri=' + encodeURIComponent(_this.redirectUri); return _this.store[_this._storage].getItem(_this.clientId + "_refresh_token") .then(function (refresh_token) { if (!refresh_token) { return _this.store[_this._storage].getItem("refreshToken").then(function (refresh_token_local) { if (refresh_token_local) { url += "&refresh_token=" + encodeURIComponent(refresh_token_local); url += "&grant_type=" + encodeURIComponent('refresh_token'); return url; } else { url += "&code=" + encodeURIComponent(_this.code) + "&"; url += "grant_type=" + encodeURIComponent('authorization_code'); return url; } }); } else { url += "&refresh_token=" + encodeURIComponent(refresh_token); url += "&grant_type=" + encodeURIComponent('refresh_token'); return url; } }); }); }; OAuthService.prototype.initImplicitFlow = function (additionalState) { var _this = this; if (additionalState === void 0) { additionalState = ''; } if (!this.clientId || this.clientId === '' || this.run_flow) { return; } this.createLoginUrl(additionalState).then(function (url) { var path = location.href; if (location.hash.indexOf(path) >= 0 && location.href.indexOf(location.origin + '/#/') >= 0) { if (path.indexOf('?') >= 0) { path = path.split('?')[0]; } } var here = path; _this.store.local.setItem("oauth_redirect", here); _this.run_flow = true; _this.store.session.getItem(_this.clientId + "_login").then(function (logged) { if (logged === 'true' && url.indexOf('http') >= 0) { COMPOSER.log('OAUTH', 'Logged in. Authorizing...'); _this.store.session.removeItem(_this.clientId + "_login"); location.href = url; } else { COMPOSER.log('OAUTH', 'Not logged in redirecting to provider...'); _this.needs_login = true; if (_this.login_local) { _this.login_obs.next(_this.needs_login); _this.run_flow = false; } else { _this.store.session.setItem(_this.clientId + "_login", 'true'); if (!_this.loginRedirect || _this.loginRedirect === '' && location.origin.indexOf('http') >= 0) { _this.loginRedirect = location.origin + '/auth/login'; } else if (_this.loginRedirect && _this.loginRedirect !== '') { COMPOSER.log('OAUTH', "Login: " + _this.loginRedirect); location.href = _this.loginRedirect; } } } }); }, function (err) { return; }); }; OAuthService.prototype.callEventIfExists = function (options) { var that = this; if (options.onTokenReceived) { var tokenParams = { idClaims: that.getIdentityClaims(), idToken: that.getIdToken(), accessToken: that.getAccessToken(), state: that.state, }; options.onTokenReceived(tokenParams); } }; OAuthService.prototype.attemptLogin = function (options, resolve, reject) { var _this = this; if (this.clientId && this.clientId !== '') { options = options || {}; var parts_1 = this.getFragment(); if (Object.keys(parts_1).length <= 1) { this.store.session.getItem('OAUTH.params').then(function (item) { if (item) { parts_1 = JSON.parse(item); } _this.store.session.removeItem('OAUTH.params'); _this.processLogin(parts_1, options, resolve, reject); }); } else { this.processLogin(parts_1, options, resolve, reject); } } else { setTimeout(function () { _this.attemptLogin(options, resolve, reject); }, 200); } }; OAuthService.prototype.processLogin = function (parts, options, resolve, reject) { var _this = this; var accessToken = parts.access_token; var idToken = parts.id_token; var state = parts.state; var code = parts.code; var refreshToken = parts.refreshToken; COMPOSER.log('OAUTH', "State: " + state); COMPOSER.log('OAUTH', "Access: " + accessToken + " | Refresh: " + accessToken); var oidcSuccess = false; var oauthSuccess = false; if ((!accessToken && !code && !refreshToken) || !state) { return resolve(false); } if (this.oidc && !idToken) { return resolve(false); } if (code) { this.code = code; } if (refreshToken) { this.store[this._storage].setItem(this.clientId + "_refresh_token", refreshToken); } this.store[this._storage].getItem(this.clientId + "_nonce") .then(function (savedNonce) { var stateParts = state.split(';'); var nonceInState = stateParts[0]; if (savedNonce === nonceInState) { if (accessToken) { _this.store[_this._storage].setItem(_this.clientId + "_access_token", accessToken); } var expiresIn = parts.expires_in; if (expiresIn) { var expiresInMilliSeconds = parseInt(expiresIn, 10) * 1000; var now = new Date(); var expiresAt = now.getTime() + expiresInMilliSeconds; _this.store[_this._storage].setItem(_this.clientId + "_expires_at", '' + expiresAt); } if (stateParts.length > 1) { _this.state = stateParts[1]; } oauthSuccess = true; } if (!oauthSuccess) { return resolve(false); } if (!_this.oidc && options.onTokenReceived) { options.onTokenReceived({ accessToken: accessToken }); } if (_this.oidc) { _this.processIdToken(idToken, accessToken).then(function (success) { if (!success) { return resolve(false); } }); } if (options.validationHandler) { var validationParams = { accessToken: accessToken, idToken: idToken }; options .validationHandler(validationParams) .then(function () { _this.callEventIfExists(options); }) .catch(function (reason) { COMPOSER.error('OAUTH', 'Error validating tokens', reason); }); } else { _this.callEventIfExists(options); } _this.store[_this._storage].removeItem('oauth_redirect'); _this.store[_this._storage].setItem('oauth_finished', 'true'); _this.location.go(_this.location.path(), ''); return resolve(true); }); }; OAuthService.prototype.processIdToken = function (idToken, accessToken) { var _this = this; return new Promise(function (resolve) { var tokenParts = idToken.split('.'); var claimsBase64 = _this.padBase64(tokenParts[1]); var claimsJson = ''; var claims = JSON.parse(claimsJson); _this.store[_this._storage].getItem(_this.clientId + "_nonce").then(function (savedNonce) { if (claims.aud !== _this.clientId) { COMPOSER.log('OAUTH', 'Wrong audience: ' + claims.aud, null, 'warn'); return resolve(false); } if (_this.issuer && claims.iss !== _this.issuer) { COMPOSER.log('OAUTH', 'Wrong issuer: ' + claims.iss, null, 'warn'); return resolve(false); } if (claims.nonce !== savedNonce) { COMPOSER.log('OAUTH', 'Wrong nonce: ' + claims.nonce, null, 'warn'); return resolve(false); } if (accessToken && !_this.checkAtHash(accessToken, claims)) { COMPOSER.log('OAUTH', 'Wrong at_hash', null, 'warn'); return resolve(false); } var now = Date.now(); var issuedAtMSec = claims.iat * 1000; var expiresAtMSec = claims.exp * 1000; var tenMinutesInMsec = 1000 * 60 * 10; if (issuedAtMSec - tenMinutesInMsec >= now || expiresAtMSec + tenMinutesInMsec <= now) { COMPOSER.log('OAUTH', 'Token has been expired', { now: now, issuedAtMSec: issuedAtMSec, expiresAtMSec: expiresAtMSec, }); return resolve(false); } _this.store[_this._storage].setItem(_this.clientId + "_id_token", idToken); _this.store[_this._storage].setItem(_this.clientId + "_id_token_claims_obj", claimsJson); _this.store[_this._storage].setItem(_this.clientId + "_id_token_expires_at", '' + expiresAtMSec); if (_this.validationHandler) { _this.validationHandler(idToken); } return resolve(true); }); }); }; OAuthService.prototype.padBase64 = function (base64data) { while (base64data.length % 4 !== 0) { base64data += '='; } return base64data; }; OAuthService.prototype.createAndSaveNonce = function () { var _this = this; return this.createNonce().then(function (nonce) { _this.store[_this._storage].setItem(_this.clientId + "_nonce", nonce); return nonce; }, function (err) { return ''; }); }; OAuthService.prototype.createNonce = function () { var _this = this; return new Promise(function (resolve, reject) { if (_this.rngUrl) { throw new Error('createNonce with rng-web-api has not been implemented so far'); } else { var text = ''; var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (var i = 0; i < 40; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } resolve(text); } }); }; OAuthService.prototype.getFragment = function () { var path = this.location.path(); if (location.hash.indexOf('#') === 0 && location.hash.indexOf(path) < 0) { return this.parseQueryString(location.hash.substr(1)); } else if (location.search.indexOf('?') === 0) { return this.parseQueryString(location.search.substr(1)); } else { return {}; } }; OAuthService.prototype.parseQueryString = function (queryString) { var data = {}; var pairs; var pair; var separatorIndex; var escapedKey; var escapedValue; var key; var value; if (queryString === null) { return data; } pairs = queryString.split('&'); for (var i = 0; i < pairs.length; i++) { pair = pairs[i]; separatorIndex = pair.indexOf('='); if (separatorIndex === -1) { escapedKey = pair; escapedValue = null; } else { escapedKey = pair.substr(0, separatorIndex); escapedValue = pair.substr(separatorIndex + 1); } key = decodeURIComponent(escapedKey); value = decodeURIComponent(escapedValue); if (key.substr(0, 1) === '/') { key = key.substr(1); } data[key] = value; } return data; }; OAuthService.prototype.checkAtHash = function (accessToken, idClaims) { if (!accessToken || !idClaims || !idClaims.at_hash) { return true; } var tokenHash = []; var leftMostHalf = tokenHash.slice(0, (tokenHash.length / 2)); var tokenHashBase64 = ''; var atHash = tokenHashBase64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); var claimsAtHash = idClaims.at_hash.replace(/=/g, ''); if (atHash !== claimsAtHash) { COMPOSER.log('OAUTH', 'exptected at_hash: ' + atHash, null, 'warn'); COMPOSER.log('OAUTH', 'actual at_hash: ' + claimsAtHash, null, 'warn'); } return (atHash === claimsAtHash); }; return OAuthService; }()); export { OAuthService }; OAuthService.decorators = [ { type: Injectable }, ]; OAuthService.ctorParameters = function () { return [ { type: Location, }, { type: DataStoreService, }, ]; }; //# sourceMappingURL=oauth2.service.js.map