mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-12 20:43:08 +00:00
Removed switch statement, changed AuthMethod parsing in authInterceptor to be more generic
This commit is contained in:
@@ -3,7 +3,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<img class="mb-4 login-logo" src="assets/images/dspace-logo.png">
|
<img class="mb-4 login-logo" src="assets/images/dspace-logo.png">
|
||||||
<h1 class="h3 mb-0 font-weight-normal">{{"login.form.header" | translate}}</h1>
|
<h1 class="h3 mb-0 font-weight-normal">{{"login.form.header" | translate}}</h1>
|
||||||
<ds-login-container></ds-login-container>
|
<!-- <ds-login-container></ds-login-container>-->
|
||||||
|
<ds-auth-methods></ds-auth-methods>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import {Observable, of as observableOf, throwError as observableThrowError} from 'rxjs';
|
import { Observable, of as observableOf, throwError as observableThrowError } from 'rxjs';
|
||||||
|
|
||||||
import {catchError, filter, map, tap} from 'rxjs/operators';
|
import { catchError, filter, map, tap } from 'rxjs/operators';
|
||||||
import {Injectable, Injector} from '@angular/core';
|
import { Injectable, Injector } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
HttpErrorResponse,
|
HttpErrorResponse,
|
||||||
HttpEvent,
|
HttpEvent,
|
||||||
@@ -11,18 +11,18 @@ import {
|
|||||||
HttpResponse,
|
HttpResponse,
|
||||||
HttpResponseBase
|
HttpResponseBase
|
||||||
} from '@angular/common/http';
|
} from '@angular/common/http';
|
||||||
import {find} from 'lodash';
|
import { find } from 'lodash';
|
||||||
|
|
||||||
import {AppState} from '../../app.reducer';
|
import { AppState } from '../../app.reducer';
|
||||||
import {AuthService} from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
import {AuthStatus} from './models/auth-status.model';
|
import { AuthStatus } from './models/auth-status.model';
|
||||||
import {AuthTokenInfo} from './models/auth-token-info.model';
|
import { AuthTokenInfo } from './models/auth-token-info.model';
|
||||||
import {isNotEmpty, isUndefined, isNotNull} from '../../shared/empty.util';
|
import { isNotEmpty, isUndefined, isNotNull } from '../../shared/empty.util';
|
||||||
import {RedirectWhenTokenExpiredAction, RefreshTokenAction} from './auth.actions';
|
import { RedirectWhenTokenExpiredAction, RefreshTokenAction } from './auth.actions';
|
||||||
import {Store} from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import {Router} from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import {AuthError} from './models/auth-error.model';
|
import { AuthError } from './models/auth-error.model';
|
||||||
import {AuthMethodModel} from './models/auth-method.model';
|
import { AuthMethodModel } from './models/auth-method.model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthInterceptor implements HttpInterceptor {
|
export class AuthInterceptor implements HttpInterceptor {
|
||||||
@@ -59,8 +59,7 @@ export class AuthInterceptor implements HttpInterceptor {
|
|||||||
return http.url && http.url.endsWith('/authn/logout');
|
return http.url && http.url.endsWith('/authn/logout');
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseShibbolethLocation(unparsedLocation: string): string {
|
private parseLocation(unparsedLocation: string): string {
|
||||||
let parsedLocation = '';
|
|
||||||
unparsedLocation = unparsedLocation.trim();
|
unparsedLocation = unparsedLocation.trim();
|
||||||
unparsedLocation = unparsedLocation.replace('location="', '');
|
unparsedLocation = unparsedLocation.replace('location="', '');
|
||||||
unparsedLocation = unparsedLocation.replace('"', '');
|
unparsedLocation = unparsedLocation.replace('"', '');
|
||||||
@@ -68,7 +67,7 @@ export class AuthInterceptor implements HttpInterceptor {
|
|||||||
unparsedLocation = unparsedLocation.replace(re, '://');
|
unparsedLocation = unparsedLocation.replace(re, '://');
|
||||||
re = /%3A/g
|
re = /%3A/g
|
||||||
unparsedLocation = unparsedLocation.replace(re, ':')
|
unparsedLocation = unparsedLocation.replace(re, ':')
|
||||||
parsedLocation = unparsedLocation + '/shibboleth';
|
const parsedLocation = unparsedLocation.trim(); // + '/shibboleth';
|
||||||
|
|
||||||
return parsedLocation;
|
return parsedLocation;
|
||||||
}
|
}
|
||||||
@@ -76,24 +75,32 @@ export class AuthInterceptor implements HttpInterceptor {
|
|||||||
private parseAuthMethodsfromHeaders(headers: HttpHeaders): AuthMethodModel[] {
|
private parseAuthMethodsfromHeaders(headers: HttpHeaders): AuthMethodModel[] {
|
||||||
const authMethodModels: AuthMethodModel[] = [];
|
const authMethodModels: AuthMethodModel[] = [];
|
||||||
const parts: string[] = headers.get('www-authenticate').split(',');
|
const parts: string[] = headers.get('www-authenticate').split(',');
|
||||||
// get the login methods names
|
// get the realms from the header - a realm is a single auth method
|
||||||
|
const completeWWWauthenticateHeader = headers.get('www-authenticate');
|
||||||
|
const regex = /(\w+ (\w+=((".*?")|[^,]*)(, )?)*)/g;
|
||||||
|
const realms = completeWWWauthenticateHeader.match(regex);
|
||||||
|
console.log('realms: ', realms)
|
||||||
|
|
||||||
// tslint:disable-next-line:forin
|
// tslint:disable-next-line:forin
|
||||||
for (const i in parts) {
|
for (const j in realms) {
|
||||||
const part: string = parts[i].trim();
|
console.log('realm:', realms[j]);
|
||||||
if (part.includes('realm')) {
|
|
||||||
const methodName = part.split(' ')[0];
|
const splittedRealm = realms[j].split(', ');
|
||||||
const authMethod: AuthMethodModel = new AuthMethodModel(methodName);
|
const methodName = splittedRealm[0].split(' ')[0].trim();
|
||||||
// check if the authentication method is shibboleth
|
console.log('methodName: ', methodName);
|
||||||
// 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://serverUrl"
|
console.log('splittedRealm: ', splittedRealm);
|
||||||
if (methodName.includes('shibboleth')) {
|
let authMethodModel: AuthMethodModel;
|
||||||
// +1: unaray + operator in the next line is necessaray because i is a string, the operator works like parseInt()
|
if (splittedRealm.length === 1) {
|
||||||
const location: string = this.parseShibbolethLocation(parts[+i + 1]);
|
authMethodModel = new AuthMethodModel(methodName);
|
||||||
authMethod.location = location;
|
authMethodModels.push(authMethodModel);
|
||||||
}
|
} else if (splittedRealm.length > 1) {
|
||||||
// if other authentication methods deliver data needed for the method to work
|
authMethodModel = new AuthMethodModel(methodName);
|
||||||
// it would be checked here e.g. if (methodName.includes('ldap')) { }
|
let location = splittedRealm[1];
|
||||||
authMethodModels.push(authMethod);
|
location = this.parseLocation(location)
|
||||||
|
authMethodModel.location = location;
|
||||||
|
console.log('location: ', location);
|
||||||
|
authMethodModels.push(authMethodModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return authMethodModels;
|
return authMethodModels;
|
||||||
|
@@ -1,12 +1,10 @@
|
|||||||
import {AuthMethodType} from '../../../shared/log-in/authMethods-type';
|
import {AuthMethodType} from '../../../shared/log-in/authMethods-type';
|
||||||
|
|
||||||
export class AuthMethodModel {
|
export class AuthMethodModel {
|
||||||
authMethodName: string;
|
authMethodType: AuthMethodType;
|
||||||
location?: string;
|
location?: string;
|
||||||
authMethodType: AuthMethodType
|
|
||||||
|
|
||||||
constructor(authMethodName: string, location?: string) {
|
constructor(authMethodName: string, location?: string) {
|
||||||
this.authMethodName = authMethodName;
|
|
||||||
this.location = location;
|
this.location = location;
|
||||||
switch (authMethodName) {
|
switch (authMethodName) {
|
||||||
case 'ip': {
|
case 'ip': {
|
||||||
|
@@ -4,7 +4,8 @@
|
|||||||
<a href="#" id="dropdownLogin" (click)="$event.preventDefault()" ngbDropdownToggle class="px-1">{{ 'nav.login' | translate }}</a>
|
<a href="#" id="dropdownLogin" (click)="$event.preventDefault()" ngbDropdownToggle class="px-1">{{ 'nav.login' | translate }}</a>
|
||||||
<div id="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu aria-labelledby="dropdownLogin">
|
<div id="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu aria-labelledby="dropdownLogin">
|
||||||
<!-- <ds-log-in></ds-log-in>-->
|
<!-- <ds-log-in></ds-log-in>-->
|
||||||
<ds-login-container></ds-login-container>
|
<!-- <ds-login-container></ds-login-container>-->
|
||||||
|
<ds-auth-methods></ds-auth-methods>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
3
src/app/shared/log-in/authMethods.component.html
Normal file
3
src/app/shared/log-in/authMethods.component.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<ng-container *ngFor="let authMethodModel of (authMethodData | async)">
|
||||||
|
<ds-login-container [authMethodModel]="authMethodModel"></ds-login-container>
|
||||||
|
</ng-container>
|
0
src/app/shared/log-in/authMethods.component.scss
Normal file
0
src/app/shared/log-in/authMethods.component.scss
Normal file
27
src/app/shared/log-in/authMethods.component.ts
Normal file
27
src/app/shared/log-in/authMethods.component.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Component, Injector, Input, OnInit } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { AuthMethodModel } from '../../core/auth/models/auth-method.model';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { AuthState } from '../../core/auth/auth.reducer';
|
||||||
|
import { getAuthenticationMethods } from '../../core/auth/selectors';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-auth-methods',
|
||||||
|
templateUrl: './authMethods.component.html',
|
||||||
|
styleUrls: ['./authMethods.component.scss']
|
||||||
|
})
|
||||||
|
export class AuthMethodsComponent implements OnInit {
|
||||||
|
/**
|
||||||
|
* The authentication methods data
|
||||||
|
* @type {AuthMethodModel[]}
|
||||||
|
*/
|
||||||
|
@Input() authMethodData: Observable<AuthMethodModel[]>;
|
||||||
|
|
||||||
|
constructor( private store: Store<AuthState>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.authMethodData = this.authMethodData = this.store.select(getAuthenticationMethods);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,3 +1,2 @@
|
|||||||
<div *ngFor="let authMethod of authMethodData | async">
|
<ng-container *ngComponentOutlet="getAuthMethodContent(); injector: objectInjector;"></ng-container>
|
||||||
<ng-container *ngComponentOutlet="getAuthMethodContent(authMethod.authMethodType); injector: objectInjector;"></ng-container>
|
|
||||||
</div>
|
|
||||||
|
@@ -17,11 +17,7 @@ import { AuthMethodType } from '../authMethods-type';
|
|||||||
})
|
})
|
||||||
export class LoginContainerComponent implements OnInit {
|
export class LoginContainerComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
@Input() authMethodModel: AuthMethodModel;
|
||||||
* The section data
|
|
||||||
* @type {SectionDataObject}
|
|
||||||
*/
|
|
||||||
@Input() authMethodData: Observable<AuthMethodModel[]>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injector to inject a section component with the @Input parameters
|
* Injector to inject a section component with the @Input parameters
|
||||||
@@ -34,7 +30,7 @@ export class LoginContainerComponent implements OnInit {
|
|||||||
*
|
*
|
||||||
* @param {Injector} injector
|
* @param {Injector} injector
|
||||||
*/
|
*/
|
||||||
constructor(private injector: Injector, private store: Store<AppState>) {
|
constructor(private injector: Injector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,18 +39,17 @@ export class LoginContainerComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.objectInjector = Injector.create({
|
this.objectInjector = Injector.create({
|
||||||
providers: [
|
providers: [
|
||||||
{provide: 'authMethodProvider', useFactory: () => (this.authMethodData), deps: []},
|
{provide: 'authMethodModelProvider', useFactory: () => (this.authMethodModel), deps: []},
|
||||||
],
|
],
|
||||||
parent: this.injector
|
parent: this.injector
|
||||||
});
|
});
|
||||||
|
|
||||||
this.authMethodData = this.store.select(getAuthenticationMethods);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the correct component based on the authMethod's type
|
* Find the correct component based on the authMethod's type
|
||||||
*/
|
*/
|
||||||
getAuthMethodContent(authMethodType: AuthMethodType): string {
|
getAuthMethodContent(): string {
|
||||||
return rendersAuthMethodType(authMethodType)
|
return rendersAuthMethodType(this.authMethodModel.authMethodType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<div>
|
<div>
|
||||||
<a class="btn btn-lg btn-primary btn-block mt-3" type="submit"
|
<a class="btn btn-lg btn-primary btn-block mt-3" type="submit"
|
||||||
[href]="injectedShibbolethUrl"
|
[href]="authMethodModel.location"
|
||||||
role="button"
|
role="button"
|
||||||
>{{"login.shibboleth" | translate}}</a>
|
>{{"login.shibboleth" | translate}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -12,14 +12,17 @@ import { AuthMethodModel } from '../../../../core/auth/models/auth-method.model'
|
|||||||
@renderAuthMethodFor(AuthMethodType.Shibboleth)
|
@renderAuthMethodFor(AuthMethodType.Shibboleth)
|
||||||
export class DynamicShibbolethComponent implements OnInit {
|
export class DynamicShibbolethComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input()authMethodModel: AuthMethodModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
constructor(@Inject('authMethodProvider') public injectedObject: AuthMethodModel) {
|
constructor(@Inject('authMethodModelProvider') public injectedAuthMethodModel: AuthMethodModel) {
|
||||||
|
this.authMethodModel = injectedAuthMethodModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
console.log('injectedObject', this.injectedObject)
|
console.log('injectedAuthMethodModel', this.injectedAuthMethodModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -141,6 +141,7 @@ import {DynamicShibbolethComponent} from './log-in/methods/shibboleth/dynamic-sh
|
|||||||
// import {LogInComponent} from './log-in/log-in.component';
|
// import {LogInComponent} from './log-in/log-in.component';
|
||||||
import {LogInPasswordComponent} from './log-in/methods/password/log-in-password.component';
|
import {LogInPasswordComponent} from './log-in/methods/password/log-in-password.component';
|
||||||
import { LoginContainerComponent } from './log-in/container/login-container.component';
|
import { LoginContainerComponent } from './log-in/container/login-container.component';
|
||||||
|
import { AuthMethodsComponent } from './log-in/authMethods.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -264,7 +265,8 @@ const COMPONENTS = [
|
|||||||
// LogInComponent,
|
// LogInComponent,
|
||||||
DynamicShibbolethComponent,
|
DynamicShibbolethComponent,
|
||||||
LogInPasswordComponent,
|
LogInPasswordComponent,
|
||||||
LoginContainerComponent
|
LoginContainerComponent,
|
||||||
|
AuthMethodsComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
const ENTRY_COMPONENTS = [
|
const ENTRY_COMPONENTS = [
|
||||||
|
Reference in New Issue
Block a user