diff --git a/.vscode/launch.json b/.vscode/launch.json index fb054eac83..08f1196558 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "name": "e2e", "program": "${workspaceFolder}/node_modules/protractor/bin/protractor", "args": [ - "`${workspaceFolder}/.vscode/closest-config-finder.sh ${file} e2e/protractor.conf.js`", + "./e2e/protractor.conf.js", "--specs=${file}" ], "envFile": "${workspaceFolder}/.env", diff --git a/lib/core/src/lib/auth/interfaces/authentication-service.interface.ts b/lib/core/src/lib/auth/interfaces/authentication-service.interface.ts index a394e81af6..2c9b924129 100644 --- a/lib/core/src/lib/auth/interfaces/authentication-service.interface.ts +++ b/lib/core/src/lib/auth/interfaces/authentication-service.interface.ts @@ -17,6 +17,7 @@ import { HttpHeaders } from '@angular/common/http'; import ee from 'event-emitter'; +import { Observable } from 'rxjs'; export interface AuthenticationServiceInterface { @@ -53,5 +54,7 @@ export interface AuthenticationServiceInterface { getAuthHeaders(requestUrl: string, header: HttpHeaders): HttpHeaders; + addTokenToHeader(requestUrl: string, headersArg?: HttpHeaders): Observable; + reset(): void; } diff --git a/lib/core/src/lib/auth/oidc/auth.service.ts b/lib/core/src/lib/auth/oidc/auth.service.ts index 4c3be8fc7f..be027665ab 100644 --- a/lib/core/src/lib/auth/oidc/auth.service.ts +++ b/lib/core/src/lib/auth/oidc/auth.service.ts @@ -22,6 +22,8 @@ import { Observable } from 'rxjs'; * Provide authentication/authorization through OAuth2/OIDC protocol. */ export abstract class AuthService { + abstract onLogin: Observable; + /** Subscribe to whether the user has valid Id/Access tokens. */ abstract authenticated$: Observable; diff --git a/lib/core/src/lib/auth/oidc/redirect-auth.service.ts b/lib/core/src/lib/auth/oidc/redirect-auth.service.ts index 0e87c75bed..98cf9e8732 100644 --- a/lib/core/src/lib/auth/oidc/redirect-auth.service.ts +++ b/lib/core/src/lib/auth/oidc/redirect-auth.service.ts @@ -19,13 +19,16 @@ import { Inject, Injectable } from '@angular/core'; import { AuthConfig, AUTH_CONFIG, OAuthErrorEvent, OAuthService, OAuthStorage, TokenResponse } from 'angular-oauth2-oidc'; import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks'; import { from, Observable } from 'rxjs'; -import { distinctUntilChanged, filter, map, shareReplay, startWith } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map, shareReplay } from 'rxjs/operators'; import { AuthService } from './auth.service'; const isPromise = (value: T | Promise): value is Promise => value && typeof (value as Promise).then === 'function'; @Injectable() export class RedirectAuthService extends AuthService { + + onLogin: Observable; + private _loadDiscoveryDocumentPromise = Promise.resolve(false); /** Subscribe to whether the user has valid Id/Access tokens. */ @@ -48,29 +51,32 @@ export class RedirectAuthService extends AuthService { ) { super(); this.authConfig = authConfig; - } - init() { this.oauthService.clearHashAfterLogin = true; this.authenticated$ = this.oauthService.events.pipe( - startWith(undefined), map(() => this.authenticated), distinctUntilChanged(), shareReplay(1) ); + this.onLogin = this.authenticated$.pipe( + filter((authenticated) => authenticated), + map(() => undefined) + ); + this.idpUnreachable$ = this.oauthService.events.pipe( filter((event): event is OAuthErrorEvent => event.type === 'discovery_document_load_error'), map((event) => event.reason as Error) ); + } + init() { if (isPromise(this.authConfig)) { return this.authConfig.then((config) => this.configureAuth(config)); } return this.configureAuth(this.authConfig); - } logout() { diff --git a/lib/core/src/lib/auth/services/authentication.service.ts b/lib/core/src/lib/auth/services/authentication.service.ts index 6670be7f82..3680f52db6 100644 --- a/lib/core/src/lib/auth/services/authentication.service.ts +++ b/lib/core/src/lib/auth/services/authentication.service.ts @@ -18,28 +18,64 @@ import { Injectable, Injector } from '@angular/core'; import { OidcAuthenticationService } from './oidc-authentication.service'; import { BasicAlfrescoAuthService } from '../basic-auth/basic-alfresco-auth.service'; -import { Observable, from } from 'rxjs'; -import { BaseAuthenticationService } from './base-authentication.service'; -import { AppConfigService } from '../../app-config'; -import { CookieService, LogService } from '../../common'; +import { Observable, from, merge } from 'rxjs'; import { HttpHeaders } from '@angular/common/http'; -import { tap } from 'rxjs/operators'; +import { AuthenticationServiceInterface } from '../interfaces/authentication-service.interface'; +import ee from 'event-emitter'; +import { RedirectAuthService } from '../oidc/redirect-auth.service'; @Injectable({ providedIn: 'root' }) -export class AuthenticationService extends BaseAuthenticationService { +export class AuthenticationService implements AuthenticationServiceInterface, ee.Emitter { - constructor(appConfig: AppConfigService, - cookie: CookieService, - logService: LogService, - private injector: Injector) { - super(appConfig, cookie, logService); + onLogin: Observable; - (this.isOauth() ? this.oidcAuthenticationService.onLogin : this.basicAlfrescoAuthService.onLogin) - .pipe( - tap(() => this.onLogin.next()) - ).subscribe(); + constructor( + private injector: Injector, + private redirectAuthService: RedirectAuthService + ) { + this.onLogin = merge(this.redirectAuthService.onLogin, this.basicAlfrescoAuthService.onLogin); + } + + get on(): ee.EmitterMethod { + return this.isOauth() ? this.oidcAuthenticationService.on : this.basicAlfrescoAuthService.on; + } + + get off(): ee.EmitterMethod { + return this.isOauth() ? this.oidcAuthenticationService.off : this.basicAlfrescoAuthService.off; + } + + get once(): ee.EmitterMethod { + return this.isOauth() ? this.oidcAuthenticationService.once : this.basicAlfrescoAuthService.once; + } + + get emit(): (type: string, ...args: any[]) => void { + return this.isOauth() ? this.oidcAuthenticationService.emit : this.basicAlfrescoAuthService.emit; + } + + get onLogout(): Observable { + return this.isOauth() ? this.oidcAuthenticationService.onLogout : this.basicAlfrescoAuthService.onLogout; + } + + get onError(): Observable { + return this.isOauth() ? this.oidcAuthenticationService.onError : this.basicAlfrescoAuthService.onError; + } + + addTokenToHeader(requestUrl: string, headersArg?: HttpHeaders): Observable { + return this.isOauth() ? this.oidcAuthenticationService.addTokenToHeader(requestUrl, headersArg) : from([headersArg]); + } + + isECMProvider(): boolean { + return this.isOauth() ? this.oidcAuthenticationService.isECMProvider() : this.basicAlfrescoAuthService.isECMProvider(); + } + + isBPMProvider(): boolean { + return this.isOauth() ? this.oidcAuthenticationService.isBPMProvider() : this.basicAlfrescoAuthService.isBPMProvider(); + } + + isALLProvider(): boolean { + return this.isOauth() ? this.oidcAuthenticationService.isALLProvider() : this.basicAlfrescoAuthService.isALLProvider(); } private get oidcAuthenticationService(): OidcAuthenticationService { @@ -121,4 +157,8 @@ export class AuthenticationService extends BaseAuthenticationService { return this.basicAlfrescoAuthService.getAuthHeaders(requestUrl, headers); } } + + isOauth(): boolean { + return this.basicAlfrescoAuthService.isOauth(); + } } diff --git a/lib/core/src/lib/auth/services/base-authentication.service.ts b/lib/core/src/lib/auth/services/base-authentication.service.ts index 6d79ff6aa3..19fc315684 100644 --- a/lib/core/src/lib/auth/services/base-authentication.service.ts +++ b/lib/core/src/lib/auth/services/base-authentication.service.ts @@ -24,7 +24,7 @@ import { LogService } from '../../common/services/log.service'; import { AuthenticationServiceInterface } from '../interfaces/authentication-service.interface'; import ee from 'event-emitter'; -export abstract class BaseAuthenticationService implements AuthenticationServiceInterface, ee.Emitter { +export abstract class BaseAuthenticationService implements AuthenticationServiceInterface, ee.Emitter { on: ee.EmitterMethod; off: ee.EmitterMethod;