diff --git a/src/app/core/auth/auth.interceptor.ts b/src/app/core/auth/auth.interceptor.ts index 5803f0a4c8..cab03c2f4a 100644 --- a/src/app/core/auth/auth.interceptor.ts +++ b/src/app/core/auth/auth.interceptor.ts @@ -65,16 +65,53 @@ export class AuthInterceptor implements HttpInterceptor { return http.url && http.url.endsWith('/authn/logout'); } - private parseAuthMethodsfromHeaders(headers: HttpHeaders): AuthMethodModel[] { - console.log('parseAuthMethodsfromHeaders(): ', headers); - // errorHeaders - return []; + private parseShibbolethLocation(unparsedLocation: string): string { + let parsedLocation = ''; + unparsedLocation = unparsedLocation.trim(); + unparsedLocation = unparsedLocation.replace('location="', ''); + unparsedLocation = unparsedLocation.replace('"', ''); + let re = /%3A%2F%2F/g; + unparsedLocation = unparsedLocation.replace(re, '://'); + re = /%3A/g + unparsedLocation = unparsedLocation.replace(re, ':') + parsedLocation = unparsedLocation + '/shibboleth'; + + return parsedLocation; } - private makeAuthStatusObject(authenticated: boolean, accessToken?: string, error?: string, location?: string, httpHeaders?: HttpHeaders, ): AuthStatus { + private parseAuthMethodsfromHeaders(headers: HttpHeaders): AuthMethodModel[] { + // console.log('parseAuthMethodsfromHeaders(): ', headers); + const authMethodModels: AuthMethodModel[] = []; + const parts: string[] = headers.get('www-authenticate').split(','); + console.log('parts: ', parts); + // get the login methods names + // tslint:disable-next-line:forin + for (const i in parts) { + const part: string = parts[i].trim(); + if (part.includes('realm')) { + const methodName = part.split(' ')[0]; + const authMethod: AuthMethodModel = new AuthMethodModel(methodName); + // check if the authentication method is shibboleth + // if so the next part is the shibboleth location + // e.g part i: shibboleth realm="DSpace REST API", part i+1: location="/Shibboleth.sso/Login?target=https%3A%2F%2Flocalhost%3A8080" + if (methodName.includes('shibboleth')) { + console.log('Index 2: ', parts[2]); + const location: string = this.parseShibbolethLocation(parts[+i + 1]); // +1: unaray + operator is necessaray because i is a string, the operator works like parseInt() + // console.log('shib location: ', location); + authMethod.location = location; + } + authMethodModels.push(authMethod); + } + } + console.log('Array of AuthMethodModels: ', authMethodModels); + return authMethodModels; + } + + private makeAuthStatusObject(authenticated: boolean, accessToken?: string, error?: string, location?: string, httpHeaders?: HttpHeaders,): AuthStatus { const authStatus = new AuthStatus(); const authMethods: AuthMethodModel[] = this.parseAuthMethodsfromHeaders(httpHeaders); + authStatus.authMethods = authMethods; authStatus.id = null; authStatus.okay = true; @@ -193,7 +230,7 @@ export class AuthInterceptor implements HttpInterceptor { } // Create a new HttpResponse and return it, so it can be handle properly by AuthService. const authResponse = new HttpResponse({ - body: this.makeAuthStatusObject(false, null, error.error, location, error.headers ), + body: this.makeAuthStatusObject(false, null, error.error, location, error.headers), headers: error.headers, status: error.status, statusText: error.statusText, diff --git a/src/app/core/auth/auth.reducer.ts b/src/app/core/auth/auth.reducer.ts index 745a8debe3..bb92a77901 100644 --- a/src/app/core/auth/auth.reducer.ts +++ b/src/app/core/auth/auth.reducer.ts @@ -14,6 +14,7 @@ import { // import models import { EPerson } from '../eperson/models/eperson.model'; import { AuthTokenInfo } from './models/auth-token-info.model'; +import {AuthMethodModel} from './models/auth-method.model'; /** * The auth state. @@ -50,6 +51,10 @@ export interface AuthState { // the authenticated user user?: EPerson; + + // all authenticationMethods enabled at the backend + authMethods?: AuthMethodModel[]; + } /** @@ -59,7 +64,8 @@ const initialState: AuthState = { authenticated: false, loaded: false, loading: false, - ssoLoginUrl: '' + ssoLoginUrl: '', + authMethods: new Array() }; /** @@ -200,15 +206,16 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut // next three cases are used by shibboleth login case AuthActionTypes.RETRIEVE_AUTH_METHODS: - console.log(' case AuthActionTypes.RETRIEVE_AUTH_METHODS'); + console.log('case AuthActionTypes.RETRIEVE_AUTH_METHODS'); return Object.assign({}, state, { loading: true }); case AuthActionTypes.RETRIEVE_AUTH_METHODS_SUCCESS: + console.log('case RETRIEVE_AUTH_METHODS_SUCCESS'); return Object.assign({}, state, { loading: false, - ssoLoginUrl: (action as RetrieveAuthMethodsSuccessAction).payload + authMethods: (action as RetrieveAuthMethodsSuccessAction).payload }); case AuthActionTypes.RETRIEVE_AUTH_METHODS_ERROR: diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 7698d605c7..dfde0b18b6 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -24,6 +24,7 @@ import {Base64EncodeUrl} from '../../shared/utils/encode-decode.util'; import {RemoteDataBuildService} from '../cache/builders/remote-data-build.service'; import {GlobalConfig} from '../../../config/global-config.interface'; import {GLOBAL_CONFIG} from '../../../config'; +import {AuthMethodModel} from './models/auth-method.model'; export const LOGIN_ROUTE = '/login'; export const LOGOUT_ROUTE = '/logout'; @@ -222,19 +223,19 @@ export class AuthService { * Retrieve authentication methods available * @returns {User} */ - public retrieveAuthMethods(): Observable { + public retrieveAuthMethods(): Observable { console.log('auth.service retrieveAuthMethods() was called'); // return this.authRequestService.getRequest('login').pipe( return this.authRequestService.postToEndpoint('login', {}).pipe( map((status: AuthStatus) => { - let url = ''; - if (isNotEmpty(status.ssoLoginUrl)) { + let authMethods: AuthMethodModel[]; + if (isNotEmpty(status.authMethods)) { // url = this.parseSSOLocation(status.ssoLoginUrl); // console.log('Parsed SSOLoginUrl: ', url); // url = 'https://fis.tiss.tuwien.ac.at/Shibboleth.sso/Login?target=https://fis.tiss.tuwien.ac.at'; - url = status.ssoLoginUrl; + authMethods = status.authMethods; } - return url; + return authMethods; }) ) } diff --git a/src/app/core/auth/models/auth-method.model.ts b/src/app/core/auth/models/auth-method.model.ts index f27368f68d..8cca76e1ae 100644 --- a/src/app/core/auth/models/auth-method.model.ts +++ b/src/app/core/auth/models/auth-method.model.ts @@ -1,4 +1,9 @@ export class AuthMethodModel { authMethodName: string; location?: string; + + constructor(authMethodName: string, location?: string) { + this.authMethodName = authMethodName; + this.location = location; + } } diff --git a/src/app/core/auth/models/auth-status.model.ts b/src/app/core/auth/models/auth-status.model.ts index 5299b5978b..e4db209f30 100644 --- a/src/app/core/auth/models/auth-status.model.ts +++ b/src/app/core/auth/models/auth-status.model.ts @@ -53,8 +53,9 @@ export class AuthStatus implements CacheableObject { */ self: string; - ssoLoginUrl: string; - + /** + * All authentication methods enabled at the backend + */ authMethods: AuthMethodModel[]; }