Store available authentication methods in ngrx/store

This commit is contained in:
Julius Gruber
2019-08-05 14:45:57 +02:00
parent 7a3155f2b4
commit c8f4db618e
5 changed files with 67 additions and 16 deletions

View File

@@ -65,16 +65,53 @@ export class AuthInterceptor implements HttpInterceptor {
return http.url && http.url.endsWith('/authn/logout'); return http.url && http.url.endsWith('/authn/logout');
} }
private parseAuthMethodsfromHeaders(headers: HttpHeaders): AuthMethodModel[] { private parseShibbolethLocation(unparsedLocation: string): string {
console.log('parseAuthMethodsfromHeaders(): ', headers); let parsedLocation = '';
// errorHeaders unparsedLocation = unparsedLocation.trim();
return []; 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 authStatus = new AuthStatus();
const authMethods: AuthMethodModel[] = this.parseAuthMethodsfromHeaders(httpHeaders); const authMethods: AuthMethodModel[] = this.parseAuthMethodsfromHeaders(httpHeaders);
authStatus.authMethods = authMethods;
authStatus.id = null; authStatus.id = null;
authStatus.okay = true; 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. // Create a new HttpResponse and return it, so it can be handle properly by AuthService.
const authResponse = new HttpResponse({ 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, headers: error.headers,
status: error.status, status: error.status,
statusText: error.statusText, statusText: error.statusText,

View File

@@ -14,6 +14,7 @@ import {
// import models // import models
import { EPerson } from '../eperson/models/eperson.model'; import { EPerson } from '../eperson/models/eperson.model';
import { AuthTokenInfo } from './models/auth-token-info.model'; import { AuthTokenInfo } from './models/auth-token-info.model';
import {AuthMethodModel} from './models/auth-method.model';
/** /**
* The auth state. * The auth state.
@@ -50,6 +51,10 @@ export interface AuthState {
// the authenticated user // the authenticated user
user?: EPerson; user?: EPerson;
// all authenticationMethods enabled at the backend
authMethods?: AuthMethodModel[];
} }
/** /**
@@ -59,7 +64,8 @@ const initialState: AuthState = {
authenticated: false, authenticated: false,
loaded: false, loaded: false,
loading: false, loading: false,
ssoLoginUrl: '' ssoLoginUrl: '',
authMethods: new Array<AuthMethodModel>()
}; };
/** /**
@@ -200,15 +206,16 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
// next three cases are used by shibboleth login // next three cases are used by shibboleth login
case AuthActionTypes.RETRIEVE_AUTH_METHODS: case AuthActionTypes.RETRIEVE_AUTH_METHODS:
console.log(' case AuthActionTypes.RETRIEVE_AUTH_METHODS'); console.log('case AuthActionTypes.RETRIEVE_AUTH_METHODS');
return Object.assign({}, state, { return Object.assign({}, state, {
loading: true loading: true
}); });
case AuthActionTypes.RETRIEVE_AUTH_METHODS_SUCCESS: case AuthActionTypes.RETRIEVE_AUTH_METHODS_SUCCESS:
console.log('case RETRIEVE_AUTH_METHODS_SUCCESS');
return Object.assign({}, state, { return Object.assign({}, state, {
loading: false, loading: false,
ssoLoginUrl: (action as RetrieveAuthMethodsSuccessAction).payload authMethods: (action as RetrieveAuthMethodsSuccessAction).payload
}); });
case AuthActionTypes.RETRIEVE_AUTH_METHODS_ERROR: case AuthActionTypes.RETRIEVE_AUTH_METHODS_ERROR:

View File

@@ -24,6 +24,7 @@ import {Base64EncodeUrl} from '../../shared/utils/encode-decode.util';
import {RemoteDataBuildService} from '../cache/builders/remote-data-build.service'; import {RemoteDataBuildService} from '../cache/builders/remote-data-build.service';
import {GlobalConfig} from '../../../config/global-config.interface'; import {GlobalConfig} from '../../../config/global-config.interface';
import {GLOBAL_CONFIG} from '../../../config'; import {GLOBAL_CONFIG} from '../../../config';
import {AuthMethodModel} from './models/auth-method.model';
export const LOGIN_ROUTE = '/login'; export const LOGIN_ROUTE = '/login';
export const LOGOUT_ROUTE = '/logout'; export const LOGOUT_ROUTE = '/logout';
@@ -222,19 +223,19 @@ export class AuthService {
* Retrieve authentication methods available * Retrieve authentication methods available
* @returns {User} * @returns {User}
*/ */
public retrieveAuthMethods(): Observable<string> { public retrieveAuthMethods(): Observable<AuthMethodModel[]> {
console.log('auth.service retrieveAuthMethods() was called'); console.log('auth.service retrieveAuthMethods() was called');
// return this.authRequestService.getRequest('login').pipe( // return this.authRequestService.getRequest('login').pipe(
return this.authRequestService.postToEndpoint('login', {}).pipe( return this.authRequestService.postToEndpoint('login', {}).pipe(
map((status: AuthStatus) => { map((status: AuthStatus) => {
let url = ''; let authMethods: AuthMethodModel[];
if (isNotEmpty(status.ssoLoginUrl)) { if (isNotEmpty(status.authMethods)) {
// url = this.parseSSOLocation(status.ssoLoginUrl); // url = this.parseSSOLocation(status.ssoLoginUrl);
// console.log('Parsed SSOLoginUrl: ', url); // console.log('Parsed SSOLoginUrl: ', url);
// url = 'https://fis.tiss.tuwien.ac.at/Shibboleth.sso/Login?target=https://fis.tiss.tuwien.ac.at'; // 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;
}) })
) )
} }

View File

@@ -1,4 +1,9 @@
export class AuthMethodModel { export class AuthMethodModel {
authMethodName: string; authMethodName: string;
location?: string; location?: string;
constructor(authMethodName: string, location?: string) {
this.authMethodName = authMethodName;
this.location = location;
}
} }

View File

@@ -53,8 +53,9 @@ export class AuthStatus implements CacheableObject {
*/ */
self: string; self: string;
ssoLoginUrl: string; /**
* All authentication methods enabled at the backend
*/
authMethods: AuthMethodModel[]; authMethods: AuthMethodModel[];
} }