Commit 6204a5d0 authored by Eduardo Sanz García's avatar Eduardo Sanz García
Browse files

feat: WIP added TokenService interface

parent 60894709
{
"$schema": "./node_modules/ng-packagr/ng-package.schema.json",
"name": "testo",
"lib": {
"entryFile": "public_api.ts"
"entryFile": "public_api.ts",
"licensePath": "LICENSE"
}
}
{
"name": "angular-aap-auth",
"version": "1.0.0-dev.1",
"version": "1.0.0-alpha.1",
"license": "Apache-2.0",
"scripts": {
"ng": "ng",
......@@ -15,7 +15,7 @@
"keywords": [
"angular",
"jwt",
"auth"
"authentication"
],
"repository": {
"type": "git",
......@@ -25,17 +25,18 @@
"url": "https://gitlab.ebi.ac.uk/tools-glue/angular-aap-auth/issues"
},
"dependencies": {
"@angular/core": "^5.2.2",
"@auth0/angular-jwt": "^1.0.0-beta.9",
"core-js": "^2.5.3",
"rxjs": "^5.5.6",
"zone.js": "^0.8.20"
"@auth0/angular-jwt": "^1.0.0-beta.9"
},
"peerDependencies": {
"@angular/core": ">=4.3.0 <6.0.0",
"rxjs": ">=5.5.0 <6.0.0"
},
"devDependencies": {
"@angular/cli": "1.6.6",
"@angular/common": "^5.2.2",
"@angular/compiler": "^5.2.2",
"@angular/cli": "1.6.6",
"@angular/compiler-cli": "^5.2.2",
"@angular/core": "^5.2.2",
"@angular/language-service": "^5.2.2",
"@angular/platform-browser": "^5.2.2",
"@angular/platform-browser-dynamic": "^5.2.2",
......@@ -43,6 +44,7 @@
"@types/jasminewd2": "~2.0.3",
"@types/node": "~9.4.0",
"codelyzer": "^4.1.0",
"core-js": "^2.5.3",
"jasmine-core": "~2.9.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~2.0.0",
......@@ -53,8 +55,10 @@
"ncu": "^0.2.1",
"ng-packagr": "^1.6.0",
"protractor": "~5.3.0",
"rxjs": ">=5.5.0 <6.0.0",
"ts-node": "~4.1.0",
"tslint": "~5.9.1",
"typescript": "~2.6.2"
"typescript": ">=2.4.2 <2.7.0",
"zone.js": "^0.8.20"
}
}
......@@ -13,6 +13,9 @@ import {
import {
AuthService
} from './auth.service';
import {
TokenService
} from './token.service';
import {
JWT_OPTIONS,
JwtHelperService
......@@ -36,6 +39,7 @@ export class AuthModule {
useValue: options ? options : DEFAULT_CONF
},
AuthService,
TokenService,
{
provide: JWT_OPTIONS,
useValue: options ? {
......
......@@ -19,10 +19,10 @@ import {
AuthConfig
} from './auth.config';
import {
JwtHelperService
} from '@auth0/angular-jwt';
TokenService
} from './token.service';
interface LoginOptions {
export interface LoginOptions {
[key: string]: string
}
......@@ -54,7 +54,7 @@ export class AuthService {
constructor(
private _rendererFactory: RendererFactory2,
private _jwt: JwtHelperService,
private _tokenService: TokenService,
@Inject(AAP_CONFIG) private config: AuthConfig
) {
this.domain = encodeURIComponent(window.location.origin);
......@@ -85,6 +85,9 @@ export class AuthService {
/**
* Functions that opens a window instead of a tab.
*
* See method _filterLoginOptions regarding security risks of certain
* LoginOptions.
*
* @param {LoginOptions} loginOptions Options passed as URL parameters to the SSO.
* @param {number} width Pixel width of the login window.
* @param {number} height Pixel height of the login window.
......@@ -132,6 +135,9 @@ export class AuthService {
/**
* Functions that opens a tab (in modern browser).
*
* See method _filterLoginOptions regarding security risks of certain
* LoginOptions.
*
* @param {LoginOptions} loginOptions Options passed as URL parameters to the SSO.
*/
public tabOpen(loginOptions?: LoginOptions) {
......@@ -146,22 +152,63 @@ export class AuthService {
* The URL cans be opened in a new tab using target="_blank",
* or in a new window using window.open().
*
* See method _filterLoginOptions regarding security risks of certain
* LoginOptions.
*
* @param {LoginOptions} loginOptions Options passed as URL parameters to the SSO.
*
* @returnType { string } The SSO URL.
*
*/
public getSSOURL(options?: LoginOptions): string {
let extra = '';
if (options) {
extra = Object.entries(options).reduce((accumulator, keyvalue) => `${accumulator}&${keyvalue[0]}=${keyvalue[1]}`, '');
this._filterLoginOptions(options);
extra = Object.keys(options)
.map(key => [key, options[key]])
.reduce((accumulator, keyvalue) => `${accumulator}&${keyvalue[0]}=${keyvalue[1]}`, '');
}
return `${this.aapURL}/sso?from=${this.domain}${extra}`;
}
/**
* Filters options that are unsecure.
*
* See the advance options that can be requested through the options parameter:
* https://api.aai.ebi.ac.uk/docs/authentication/authentication.index.html#_common_attributes
*
* The time to live paramenter (ttl) default value is 60 minutes. It is a
* big security risk to request longer ttl. If a third party gets hold of
* such token, means that they could use it for a day, week, year
* (essentially, like having the username/password).
*
* @param {LoginOptions} loginOptions Options passed as URL parameters to the SSO.
*
* @returnType { void }
*
*/
public _filterLoginOptions(options: LoginOptions) {
if (Object.keys(options).indexOf('ttl') > -1) {
const ttl: number = +options['ttl'];
const softLimit = 60;
const hardLimit = 60 * 24;
if (ttl > hardLimit) {
window.console.error(`Login requested with an expiration longer than ${hardLimit} minutes! This is not allowed.`);
window.console.error(`Expiration request reset to ${hardLimit} minutes.`)
options['ttl'] = '' + hardLimit;
} else if (ttl > softLimit) {
window.console.warn(`Login requested with an expiration longer than ${softLimit} minutes!`);
}
}
}
/**
* Functions that logs out the user.
* It triggers the logout callbacks.
* It is an arrow function (lambda) because in that way it has a reference
* to 'this' when used in setTimeout call.
*/
public logOut(): void {
public logOut = () => {
this.storageRemover();
this._updateCredentials();
this._logoutCallbacks.map(callback => callback && callback());
......@@ -262,8 +309,8 @@ export class AuthService {
window.clearTimeout(this._timeoutID);
}
// Coercing dates to numbers with the unary operator '+'
const delay = +this._jwt.getTokenExpirationDate() - +new Date();
this._timeoutID = window.setTimeout(this.logOut.bind(this), delay);
const delay = +this._tokenService.getTokenExpirationDate() - +new Date();
this._timeoutID = window.setTimeout(this.logOut, delay);
} else {
this._username.next(null);
this._realname.next(null);
......@@ -277,38 +324,19 @@ export class AuthService {
* authenticated requests or not.
*/
private _loggedIn(): boolean {
try {
return !this._jwt.isTokenExpired();
} catch (error) {
return false
}
return this._tokenService.isTokenValid();
}
private _getUserName(): string | null {
return this._getClaim < string, null > ('email', null);
private _getToken(): string | null {
return this._tokenService.getToken();
}
private _getRealName(): string | null {
return this._getClaim < string, null > ('name', null);
private _getUserName(): string | null {
return this._tokenService.getClaim < string, null > ('email', null);
}
private _getToken(): string | null {
return this._jwt.tokenGetter();
private _getRealName(): string | null {
return this._tokenService.getClaim < string, null > ('name', null);
}
/**
* Get claims from the token.
*
* @param {string} The name of the claim
* @param {any} The default value in case of error
*
* @returnType { any } Claim
*/
private _getClaim < T, C > (claim: string, defaultValue: C): T | C {
try {
return <T > this._jwt.decodeToken()[claim];
} catch (e) {
return defaultValue;
}
}
}
import { TestBed, inject } from '@angular/core/testing';
import { TokenService } from './token.service';
describe('TokenService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [TokenService]
});
});
it('should be created', inject([TokenService], (service: TokenService) => {
expect(service).toBeTruthy();
}));
});
import {
Injectable
} from '@angular/core';
import {
JwtHelperService
} from '@auth0/angular-jwt';
/**
* The purpose of this very simple service is to interface between the
* AuthService and the specific token manipulation routing of JwtHelperService.
* In this way, if in the future we want to replace JwtHelperService by
* another service, AuthService doesn't need to be modified, only this service.
*/
@Injectable()
export class TokenService {
constructor(
private _jwt: JwtHelperService
) {}
public getToken(): string | null {
return this._jwt.tokenGetter();
}
public getTokenExpirationDate(): Date {
return this._jwt.getTokenExpirationDate();
}
public isTokenValid(): boolean {
try {
return !this._jwt.isTokenExpired();
} catch (error) {
return false
}
}
/**
* Get claims from the token.
*
* @param {string} The name of the claim
* @param {any} The default value in case of error
*
* @returnType { any } Claim
*/
public getClaim < T, C > (claim: string, defaultValue: C): T | C {
try {
return < T > this._jwt.decodeToken()[claim];
} catch (e) {
return defaultValue;
}
}
}
......@@ -92,14 +92,14 @@
node-sass "^4.7.2"
"@angular/common@^5.2.2":
version "5.2.3"
resolved "https://registry.yarnpkg.com/@angular/common/-/common-5.2.3.tgz#f2a5c12ec44b73a248d8dcb2d37ac2749f091cf7"
version "5.2.4"
resolved "https://registry.yarnpkg.com/@angular/common/-/common-5.2.4.tgz#a0ee6ef65f731196d3037bce515f7bbec90740d2"
dependencies:
tslib "^1.7.1"
"@angular/compiler-cli@^5.2.2":
version "5.2.3"
resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-5.2.3.tgz#75b39a346f1b2a95ebc403016d19fc33d5315221"
version "5.2.4"
resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-5.2.4.tgz#6d236f8433abe6752441e20884e599e8aa13c567"
dependencies:
chokidar "^1.4.2"
minimist "^1.2.0"
......@@ -107,30 +107,30 @@
tsickle "^0.26.0"
"@angular/compiler@^5.2.2":
version "5.2.3"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-5.2.3.tgz#49167adb35bdb5e7e915cce912c432300fc16816"
version "5.2.4"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-5.2.4.tgz#f653176bf6c4e253b2c445a1e50941ffba009fb2"
dependencies:
tslib "^1.7.1"
"@angular/core@^5.2.2":
version "5.2.3"
resolved "https://registry.yarnpkg.com/@angular/core/-/core-5.2.3.tgz#157dcb437d085b325513689e0e4ae70182f3f708"
version "5.2.4"
resolved "https://registry.yarnpkg.com/@angular/core/-/core-5.2.4.tgz#44a59bcea87b3aac9ce8ff2ff674fe9cb60e2041"
dependencies:
tslib "^1.7.1"
"@angular/language-service@^5.2.2":
version "5.2.3"
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-5.2.3.tgz#b858c1cd3740b29de145a6d60b2562eef391d3b3"
version "5.2.4"
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-5.2.4.tgz#281631793671844ae8f6f9c0ec80b91d064db2d8"
"@angular/platform-browser-dynamic@^5.2.2":
version "5.2.3"
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-5.2.3.tgz#87d5172da2c102c3cf48da29d39e9b4b9414b419"
version "5.2.4"
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-5.2.4.tgz#708457c9aafb1b812187c95d10365685521314d4"
dependencies:
tslib "^1.7.1"
"@angular/platform-browser@^5.2.2":
version "5.2.3"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-5.2.3.tgz#953df896839879e2b8ca89a364d66e3ac1dcd167"
version "5.2.4"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-5.2.4.tgz#dcb2dc6083774dcf2e17c9e9d0653d87057bf732"
dependencies:
tslib "^1.7.1"
......@@ -178,12 +178,12 @@
"@types/jasmine" "*"
"@types/node@^6.0.46":
version "6.0.97"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.97.tgz#72199848e8f3cfa975864031ac12e0ef6ccfe054"
version "6.0.99"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.99.tgz#3169584cc922a362ec45207c957e04b0c8d8c8f5"
"@types/node@~9.4.0":
version "9.4.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.1.tgz#0f636f7837e15d2d73a7f6f3ea0e322eb2a5ab65"
version "9.4.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.3.tgz#121b21929abfa537f47099d1d0b21b337fe2c8a5"
"@types/q@^0.0.32":
version "0.0.32"
......@@ -1204,8 +1204,8 @@ chokidar@^1.4.1, chokidar@^1.4.2, chokidar@^1.6.0, chokidar@^1.7.0:
fsevents "^1.0.0"
chokidar@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.0.tgz#6686313c541d3274b2a5c01233342037948c911b"
version "2.0.1"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.1.tgz#6e67e9998fe10e8f651e975ca62460456ff8e297"
dependencies:
anymatch "^2.0.0"
async-each "^1.0.0"
......@@ -1217,6 +1217,7 @@ chokidar@^2.0.0:
normalize-path "^2.1.1"
path-is-absolute "^1.0.0"
readdirp "^2.0.0"
upath "1.0.0"
optionalDependencies:
fsevents "^1.0.0"
......@@ -1407,14 +1408,10 @@ commander@2.12.x:
version "2.12.2"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555"
commander@^2.11.0, commander@^2.12.1, commander@^2.9.0:
commander@^2.11.0, commander@^2.12.1, commander@^2.9.0, commander@~2.14.1:
version "2.14.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa"
commander@~2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
common-tags@^1.3.1:
version "1.7.2"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.7.2.tgz#24d9768c63d253a56ecff93845b44b4df1d52771"
......@@ -1542,18 +1539,16 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
copy-webpack-plugin@^4.1.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.3.1.tgz#19ba6370bf6f8e263cbd66185a2b79f2321a9302"
version "4.4.1"
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.4.1.tgz#1e8c366211db6dc2ddee40e5a3e4fc661dd149e8"
dependencies:
cacache "^10.0.1"
find-cache-dir "^1.0.0"
globby "^7.1.1"
is-glob "^4.0.0"
loader-utils "^0.2.15"
lodash "^4.3.0"
minimatch "^3.0.4"
p-limit "^1.0.0"
pify "^3.0.0"
serialize-javascript "^1.4.0"
core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.3:
......@@ -2083,8 +2078,8 @@ domutils@1.5.1:
domelementtype "1"
domutils@^1.5.1:
version "1.6.2"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.6.2.tgz#1958cc0b4c9426e9ed367fb1c8e854891b0fa3ff"
version "1.7.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
dependencies:
dom-serializer "0"
domelementtype "1"
......@@ -4460,7 +4455,11 @@ lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
lodash@^4.0.0, lodash@^4.11.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.5.0, lodash@~4.17.4:
lodash@3.x:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
lodash@^4.0.0, lodash@^4.11.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.5.0, lodash@~4.17.4:
version "4.17.5"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
......@@ -4750,8 +4749,8 @@ mississippi@^1.3.0:
through2 "^2.0.0"
mixin-deep@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.0.tgz#47a8732ba97799457c8c1eca28f95132d7e8150a"
version "1.3.1"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
dependencies:
for-in "^1.0.2"
is-extendable "^1.0.1"
......@@ -6466,7 +6465,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
rxjs@^5.5.6:
"rxjs@>=5.5.0 <6.0.0", rxjs@^5.5.6:
version "5.5.6"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.6.tgz#e31fb96d6fd2ff1fd84bcea8ae9c02d007179c02"
dependencies:
......@@ -7549,22 +7548,22 @@ typedarray@^0.0.6, typedarray@~0.0.5:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
typescript@~2.6.2:
"typescript@>=2.4.2 <2.7.0", typescript@~2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
uglify-es@^3.3.4:
version "3.3.9"
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"
version "3.3.10"
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.10.tgz#8b0b7992cebe20edc26de1bf325cef797b8f3fa5"
dependencies:
commander "~2.13.0"
commander "~2.14.1"
source-map "~0.6.1"
uglify-js@3.3.x, uglify-js@^3.0.7:
version "3.3.9"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.9.tgz#33869666c8ab7f7658ce3d22f0f1ced40097d33a"
version "3.3.10"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.10.tgz#8e47821d4cf28e14c1826a0078ba0825ed094da8"
dependencies:
commander "~2.13.0"
commander "~2.14.1"
source-map "~0.6.1"
uglify-js@^2.6, uglify-js@^2.8.29:
......@@ -7617,6 +7616,10 @@ umd@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e"
underscore.string@2.3.x:
version "2.3.3"
resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d"
underscore@~1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209"
......@@ -7678,6 +7681,13 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
upath@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.0.tgz#b4706b9461ca8473adf89133d235689ca17f3656"
dependencies:
lodash "3.x"
underscore.string "2.3.x"
upper-case@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
......@@ -8088,8 +8098,8 @@ xml2js@^0.4.17:
xmlbuilder "~9.0.1"
xmlbuilder@>=1.0.0, xmlbuilder@~9.0.1:
version "9.0.4"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f"
version "9.0.6"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.6.tgz#7c826d8d86f47884b05872cbe9d27b01bed503f6"
xmlhttprequest-ssl@~1.5.4:
version "1.5.5"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment