Refactored components' name and added missing tests

This commit is contained in:
Giuseppe Digilio
2020-01-02 18:21:47 +01:00
parent 972f0dfd60
commit fdd05d2fec
29 changed files with 637 additions and 285 deletions

View File

@@ -7,7 +7,7 @@ import { type } from '../../shared/ngrx/type';
// import models
import { EPerson } from '../eperson/models/eperson.model';
import { AuthTokenInfo } from './models/auth-token-info.model';
import { AuthMethodModel } from './models/auth-method.model';
import { AuthMethod } from './models/auth.method';
import { AuthStatus } from './models/auth-status.model';
export const AuthActionTypes = {
@@ -340,9 +340,9 @@ export class RetrieveAuthMethodsAction implements Action {
*/
export class RetrieveAuthMethodsSuccessAction implements Action {
public type: string = AuthActionTypes.RETRIEVE_AUTH_METHODS_SUCCESS;
payload: AuthMethodModel[];
payload: AuthMethod[];
constructor(authMethods: AuthMethodModel[] ) {
constructor(authMethods: AuthMethod[] ) {
this.payload = authMethods;
}
}

View File

@@ -18,13 +18,14 @@ import {
LogOutErrorAction,
LogOutSuccessAction,
RefreshTokenErrorAction,
RefreshTokenSuccessAction
RefreshTokenSuccessAction, RetrieveAuthMethodsAction, RetrieveAuthMethodsErrorAction, RetrieveAuthMethodsSuccessAction
} from './auth.actions';
import { AuthServiceStub } from '../../shared/testing/auth-service-stub';
import { authMethodsMock, AuthServiceStub } from '../../shared/testing/auth-service-stub';
import { AuthService } from './auth.service';
import { AuthState } from './auth.reducer';
import { EPersonMock } from '../../shared/testing/eperson-mock';
import { AuthStatus } from './models/auth-status.model';
describe('AuthEffects', () => {
let authEffects: AuthEffects;
@@ -153,6 +154,49 @@ describe('AuthEffects', () => {
})
});
describe('checkTokenCookie$', () => {
describe('when check token succeeded', () => {
it('should return a AUTHENTICATED action in response to a CHECK_AUTHENTICATION_TOKEN_COOKIE action when authenticated is true', () => {
spyOn((authEffects as any).authService, 'checkAuthenticationCookie').and.returnValue(
observableOf(
{ authenticated: true,
token
})
);
actions = hot('--a-', {a: {type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE}});
const expected = cold('--b-', {b: new AuthenticatedAction(token)});
expect(authEffects.checkTokenCookie$).toBeObservable(expected);
});
it('should return a RETRIEVE_AUTH_METHODS action in response to a CHECK_AUTHENTICATION_TOKEN_COOKIE action when authenticated is false', () => {
spyOn((authEffects as any).authService, 'checkAuthenticationCookie').and.returnValue(
observableOf(
{ authenticated: false })
);
actions = hot('--a-', {a: {type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE}});
const expected = cold('--b-', {b: new RetrieveAuthMethodsAction({ authenticated: false } as AuthStatus)});
expect(authEffects.checkTokenCookie$).toBeObservable(expected);
});
});
describe('when check token failed', () => {
it('should return a AUTHENTICATED_ERROR action in response to a CHECK_AUTHENTICATION_TOKEN_COOKIE action', () => {
spyOn((authEffects as any).authService, 'checkAuthenticationCookie').and.returnValue(observableThrow(new Error('Message Error test')));
actions = hot('--a-', {a: {type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE, payload: token}});
const expected = cold('--b-', {b: new AuthenticatedErrorAction(new Error('Message Error test'))});
expect(authEffects.checkTokenCookie$).toBeObservable(expected);
});
})
});
describe('refreshToken$', () => {
describe('when refresh token succeeded', () => {
@@ -204,4 +248,30 @@ describe('AuthEffects', () => {
});
})
});
describe('retrieveMethods$', () => {
describe('when retrieve authentication methods succeeded', () => {
it('should return a RETRIEVE_AUTH_METHODS_SUCCESS action in response to a RETRIEVE_AUTH_METHODS action', () => {
actions = hot('--a-', {a: {type: AuthActionTypes.RETRIEVE_AUTH_METHODS}});
const expected = cold('--b-', {b: new RetrieveAuthMethodsSuccessAction(authMethodsMock)});
expect(authEffects.retrieveMethods$).toBeObservable(expected);
});
});
describe('when retrieve authentication methods failed', () => {
it('should return a RETRIEVE_AUTH_METHODS_ERROR action in response to a RETRIEVE_AUTH_METHODS action', () => {
spyOn((authEffects as any).authService, 'retrieveAuthMethods').and.returnValue(observableThrow(''));
actions = hot('--a-', {a: {type: AuthActionTypes.RETRIEVE_AUTH_METHODS}});
const expected = cold('--b-', {b: new RetrieveAuthMethodsErrorAction()});
expect(authEffects.retrieveMethods$).toBeObservable(expected);
});
})
});
});

View File

@@ -2,9 +2,11 @@ import { Observable, of as observableOf } from 'rxjs';
import { catchError, debounceTime, filter, map, switchMap, take, tap } from 'rxjs/operators';
import { Injectable } from '@angular/core';
// import @ngrx
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Action, select, Store } from '@ngrx/store';
// import services
import { AuthService } from './auth.service';
// import actions
@@ -35,7 +37,7 @@ import { AuthTokenInfo } from './models/auth-token-info.model';
import { AppState } from '../../app.reducer';
import { isAuthenticated } from './selectors';
import { StoreActionTypes } from '../../store.actions';
import { AuthMethodModel } from './models/auth-method.model';
import { AuthMethod } from './models/auth.method';
@Injectable()
export class AuthEffects {
@@ -46,39 +48,39 @@ export class AuthEffects {
*/
@Effect()
public authenticate$: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.AUTHENTICATE),
switchMap((action: AuthenticateAction) => {
return this.authService.authenticate(action.payload.email, action.payload.password).pipe(
take(1),
map((response: AuthStatus) => new AuthenticationSuccessAction(response.token)),
catchError((error) => observableOf(new AuthenticationErrorAction(error)))
);
})
);
ofType(AuthActionTypes.AUTHENTICATE),
switchMap((action: AuthenticateAction) => {
return this.authService.authenticate(action.payload.email, action.payload.password).pipe(
take(1),
map((response: AuthStatus) => new AuthenticationSuccessAction(response.token)),
catchError((error) => observableOf(new AuthenticationErrorAction(error)))
);
})
);
@Effect()
public authenticateSuccess$: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.AUTHENTICATE_SUCCESS),
tap((action: AuthenticationSuccessAction) => this.authService.storeToken(action.payload)),
map((action: AuthenticationSuccessAction) => new AuthenticatedAction(action.payload))
);
ofType(AuthActionTypes.AUTHENTICATE_SUCCESS),
tap((action: AuthenticationSuccessAction) => this.authService.storeToken(action.payload)),
map((action: AuthenticationSuccessAction) => new AuthenticatedAction(action.payload))
);
@Effect()
public authenticated$: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.AUTHENTICATED),
switchMap((action: AuthenticatedAction) => {
return this.authService.authenticatedUser(action.payload).pipe(
map((user: EPerson) => new AuthenticatedSuccessAction((user !== null), action.payload, user)),
catchError((error) => observableOf(new AuthenticatedErrorAction(error))),);
})
);
ofType(AuthActionTypes.AUTHENTICATED),
switchMap((action: AuthenticatedAction) => {
return this.authService.authenticatedUser(action.payload).pipe(
map((user: EPerson) => new AuthenticatedSuccessAction((user !== null), action.payload, user)),
catchError((error) => observableOf(new AuthenticatedErrorAction(error))),);
})
);
// It means "reacts to this action but don't send another"
@Effect({ dispatch: false })
public authenticatedError$: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.AUTHENTICATED_ERROR),
tap((action: LogOutSuccessAction) => this.authService.removeToken())
);
ofType(AuthActionTypes.AUTHENTICATED_ERROR),
tap((action: LogOutSuccessAction) => this.authService.removeToken())
);
@Effect()
public checkToken$: Observable<Action> = this.actions$.pipe(ofType(AuthActionTypes.CHECK_AUTHENTICATION_TOKEN),
@@ -91,7 +93,7 @@ export class AuthEffects {
);
@Effect()
public checkTokenError$: Observable<Action> = this.actions$.pipe(
public checkTokenCookie$: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE),
switchMap(() => {
return this.authService.checkAuthenticationCookie().pipe(
@@ -109,32 +111,32 @@ export class AuthEffects {
@Effect()
public createUser$: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.REGISTRATION),
debounceTime(500), // to remove when functionality is implemented
switchMap((action: RegistrationAction) => {
return this.authService.create(action.payload).pipe(
map((user: EPerson) => new RegistrationSuccessAction(user)),
catchError((error) => observableOf(new RegistrationErrorAction(error)))
);
})
);
ofType(AuthActionTypes.REGISTRATION),
debounceTime(500), // to remove when functionality is implemented
switchMap((action: RegistrationAction) => {
return this.authService.create(action.payload).pipe(
map((user: EPerson) => new RegistrationSuccessAction(user)),
catchError((error) => observableOf(new RegistrationErrorAction(error)))
);
})
);
@Effect()
public refreshToken$: Observable<Action> = this.actions$.pipe(ofType(AuthActionTypes.REFRESH_TOKEN),
switchMap((action: RefreshTokenAction) => {
return this.authService.refreshAuthenticationToken(action.payload).pipe(
map((token: AuthTokenInfo) => new RefreshTokenSuccessAction(token)),
catchError((error) => observableOf(new RefreshTokenErrorAction()))
);
})
);
switchMap((action: RefreshTokenAction) => {
return this.authService.refreshAuthenticationToken(action.payload).pipe(
map((token: AuthTokenInfo) => new RefreshTokenSuccessAction(token)),
catchError((error) => observableOf(new RefreshTokenErrorAction()))
);
})
);
// It means "reacts to this action but don't send another"
@Effect({ dispatch: false })
public refreshTokenSuccess$: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.REFRESH_TOKEN_SUCCESS),
tap((action: RefreshTokenSuccessAction) => this.authService.replaceToken(action.payload))
);
ofType(AuthActionTypes.REFRESH_TOKEN_SUCCESS),
tap((action: RefreshTokenSuccessAction) => this.authService.replaceToken(action.payload))
);
/**
* When the store is rehydrated in the browser,
@@ -195,7 +197,7 @@ export class AuthEffects {
switchMap((action: RetrieveAuthMethodsAction) => {
return this.authService.retrieveAuthMethods(action.payload)
.pipe(
map((authMethodModels: AuthMethodModel[]) => new RetrieveAuthMethodsSuccessAction(authMethodModels)),
map((authMethodModels: AuthMethod[]) => new RetrieveAuthMethodsSuccessAction(authMethodModels)),
catchError((error) => observableOf(new RetrieveAuthMethodsErrorAction()))
)
})

View File

@@ -22,8 +22,8 @@ import { isNotEmpty, isNotNull, isUndefined } from '../../shared/empty.util';
import { RedirectWhenTokenExpiredAction, RefreshTokenAction } from './auth.actions';
import { Store } from '@ngrx/store';
import { Router } from '@angular/router';
import { AuthMethodModel } from './models/auth-method.model';
import { AuthMethodType } from '../../shared/log-in/methods/authMethods-type';
import { AuthMethod } from './models/auth.method';
import { AuthMethodType } from './models/auth.method-type';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
@@ -36,15 +36,30 @@ export class AuthInterceptor implements HttpInterceptor {
constructor(private inj: Injector, private router: Router, private store: Store<AppState>) {
}
/**
* Check if response status code is 401
*
* @param response
*/
private isUnauthorized(response: HttpResponseBase): boolean {
// invalid_token The access token provided is expired, revoked, malformed, or invalid for other reasons
return response.status === 401;
}
/**
* Check if response status code is 200 or 204
*
* @param response
*/
private isSuccess(response: HttpResponseBase): boolean {
return (response.status === 200 || response.status === 204);
}
/**
* Check if http request is to authn endpoint
*
* @param http
*/
private isAuthRequest(http: HttpRequest<any> | HttpResponseBase): boolean {
return http && http.url
&& (http.url.endsWith('/authn/login')
@@ -52,29 +67,47 @@ export class AuthInterceptor implements HttpInterceptor {
|| http.url.endsWith('/authn/status'));
}
/**
* Check if response is from a login request
*
* @param http
*/
private isLoginResponse(http: HttpRequest<any> | HttpResponseBase): boolean {
return http.url && http.url.endsWith('/authn/login')
}
/**
* Check if response is from a logout request
*
* @param http
*/
private isLogoutResponse(http: HttpRequest<any> | HttpResponseBase): boolean {
return http.url && http.url.endsWith('/authn/logout');
}
private parseLocation(unparsedLocation: string): string {
unparsedLocation = unparsedLocation.trim();
unparsedLocation = unparsedLocation.replace('location="', '');
unparsedLocation = unparsedLocation.replace('"', '');
/**
* Extract location url from the WWW-Authenticate header
*
* @param header
*/
private parseLocation(header: string): string {
let location = header.trim();
location = location.replace('location="', '');
location = location.replace('"', '');
let re = /%3A%2F%2F/g;
unparsedLocation = unparsedLocation.replace(re, '://');
re = /%3A/g
unparsedLocation = unparsedLocation.replace(re, ':')
const parsedLocation = unparsedLocation.trim(); // + '/shibboleth';
return parsedLocation;
location = location.replace(re, '://');
re = /%3A/g;
location = location.replace(re, ':');
return location.trim();
}
private sortAuthMethods(authMethodModels: AuthMethodModel[]): AuthMethodModel[] {
const sortedAuthMethodModels: AuthMethodModel[] = new Array<AuthMethodModel>();
/**
* Sort authentication methods list
*
* @param authMethodModels
*/
private sortAuthMethods(authMethodModels: AuthMethod[]): AuthMethod[] {
const sortedAuthMethodModels: AuthMethod[] = [];
authMethodModels.forEach((method) => {
if (method.authMethodType === AuthMethodType.Password) {
sortedAuthMethodModels.push(method);
@@ -90,10 +123,14 @@ export class AuthInterceptor implements HttpInterceptor {
return sortedAuthMethodModels;
}
private parseAuthMethodsfromHeaders(headers: HttpHeaders): AuthMethodModel[] {
let authMethodModels: AuthMethodModel[] = [];
/**
* Extract authentication methods list from the WWW-Authenticate headers
*
* @param headers
*/
private parseAuthMethodsFromHeaders(headers: HttpHeaders): AuthMethod[] {
let authMethodModels: AuthMethod[] = [];
if (isNotEmpty(headers.get('www-authenticate'))) {
const parts: string[] = headers.get('www-authenticate').split(',');
// get the realms from the header - a realm is a single auth method
const completeWWWauthenticateHeader = headers.get('www-authenticate');
const regex = /(\w+ (\w+=((".*?")|[^,]*)(, )?)*)/g;
@@ -105,15 +142,14 @@ export class AuthInterceptor implements HttpInterceptor {
const splittedRealm = realms[j].split(', ');
const methodName = splittedRealm[0].split(' ')[0].trim();
let authMethodModel: AuthMethodModel;
let authMethodModel: AuthMethod;
if (splittedRealm.length === 1) {
authMethodModel = new AuthMethodModel(methodName);
authMethodModel = new AuthMethod(methodName);
authMethodModels.push(authMethodModel);
} else if (splittedRealm.length > 1) {
let location = splittedRealm[1];
location = this.parseLocation(location);
authMethodModel = new AuthMethodModel(methodName, location);
// console.log('location: ', location);
authMethodModel = new AuthMethod(methodName, location);
authMethodModels.push(authMethodModel);
}
}
@@ -121,17 +157,25 @@ export class AuthInterceptor implements HttpInterceptor {
// make sure the email + password login component gets rendered first
authMethodModels = this.sortAuthMethods(authMethodModels);
} else {
authMethodModels.push(new AuthMethodModel(AuthMethodType.Password));
authMethodModels.push(new AuthMethod(AuthMethodType.Password));
}
return authMethodModels;
}
/**
* Generate an AuthStatus object
*
* @param authenticated
* @param accessToken
* @param error
* @param httpHeaders
*/
private makeAuthStatusObject(authenticated: boolean, accessToken ?: string, error ?: string, httpHeaders ?: HttpHeaders): AuthStatus {
const authStatus = new AuthStatus();
// let authMethods: AuthMethodModel[];
if (httpHeaders) {
authStatus.authMethods = this.parseAuthMethodsfromHeaders(httpHeaders);
authStatus.authMethods = this.parseAuthMethodsFromHeaders(httpHeaders);
}
authStatus.id = null;
@@ -149,6 +193,11 @@ export class AuthInterceptor implements HttpInterceptor {
return authStatus;
}
/**
* Intercept method
* @param req
* @param next
*/
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const authService = this.inj.get(AuthService);
@@ -182,7 +231,7 @@ export class AuthInterceptor implements HttpInterceptor {
newReq = req.clone({withCredentials: true});
}
// Pass on the new request instead of the original request.
// Pass on the new request instead of the original request.
return next.handle(newReq).pipe(
// tap((response) => console.log('next.handle: ', response)),
map((response) => {

View File

@@ -26,8 +26,8 @@ import {
import { AuthTokenInfo } from './models/auth-token-info.model';
import { EPersonMock } from '../../shared/testing/eperson-mock';
import { AuthStatus } from './models/auth-status.model';
import { AuthMethodModel } from './models/auth-method.model';
import { AuthMethodType } from '../../shared/log-in/methods/authMethods-type';
import { AuthMethod } from './models/auth.method';
import { AuthMethodType } from './models/auth.method-type';
describe('authReducer', () => {
@@ -441,8 +441,8 @@ describe('authReducer', () => {
authMethods: []
};
const authMethods = [
new AuthMethodModel(AuthMethodType.Password),
new AuthMethodModel(AuthMethodType.Shibboleth, 'location')
new AuthMethod(AuthMethodType.Password),
new AuthMethod(AuthMethodType.Shibboleth, 'location')
];
const action = new RetrieveAuthMethodsSuccessAction(authMethods);
const newState = authReducer(initialState, action);

View File

@@ -8,14 +8,14 @@ import {
LogOutErrorAction,
RedirectWhenAuthenticationIsRequiredAction,
RedirectWhenTokenExpiredAction,
RefreshTokenSuccessAction, RetrieveAuthMethodsSuccessAction,
RefreshTokenSuccessAction,
RetrieveAuthMethodsSuccessAction,
SetRedirectUrlAction
} from './auth.actions';
// import models
import { EPerson } from '../eperson/models/eperson.model';
import { AuthTokenInfo } from './models/auth-token-info.model';
import { AuthMethodModel } from './models/auth-method.model';
import { AuthMethodType } from '../../shared/log-in/methods/authMethods-type';
import { AuthMethod } from './models/auth.method';
/**
* The auth state.
@@ -50,8 +50,8 @@ export interface AuthState {
// the authenticated user
user?: EPerson;
// all authenticationMethods enabled at the backend
authMethods?: AuthMethodModel[];
// all authentication Methods enabled at the backend
authMethods?: AuthMethod[];
}

View File

@@ -25,6 +25,8 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service';
import { routeServiceStub } from '../../shared/testing/route-service-stub';
import { RouteService } from '../services/route.service';
import { authMethodsMock } from '../../shared/testing/auth-service-stub';
import { AuthMethod } from './models/auth.method';
describe('AuthService test', () => {
@@ -128,6 +130,26 @@ describe('AuthService test', () => {
expect(authService.logout.bind(null)).toThrow();
});
it('should return the authentication status object to check an Authentication Cookie', () => {
authService.checkAuthenticationCookie().subscribe((status: AuthStatus) => {
expect(status).toBeDefined();
});
});
it('should return the authentication methods available', () => {
const authStatus = new AuthStatus();
authService.retrieveAuthMethods(authStatus).subscribe((authMethods: AuthMethod[]) => {
expect(authMethods).toBeDefined();
expect(authMethods.length).toBe(0);
});
authStatus.authMethods = authMethodsMock;
authService.retrieveAuthMethods(authStatus).subscribe((authMethods: AuthMethod[]) => {
expect(authMethods).toBeDefined();
expect(authMethods.length).toBe(2);
});
});
});
describe('', () => {

View File

@@ -27,9 +27,7 @@ import { NativeWindowRef, NativeWindowService } from '../services/window.service
import { Base64EncodeUrl } from '../../shared/utils/encode-decode.util';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { RouteService } from '../services/route.service';
import { GlobalConfig } from '../../../config/global-config.interface';
import { GLOBAL_CONFIG } from '../../../config';
import { AuthMethodModel } from './models/auth-method.model';
import { AuthMethod } from './models/auth.method';
export const LOGIN_ROUTE = '/login';
export const LOGOUT_ROUTE = '/logout';
@@ -213,8 +211,8 @@ export class AuthService {
* Retrieve authentication methods available
* @returns {User}
*/
public retrieveAuthMethods(status: AuthStatus): Observable<AuthMethodModel[]> {
let authMethods: AuthMethodModel[] = [];
public retrieveAuthMethods(status: AuthStatus): Observable<AuthMethod[]> {
let authMethods: AuthMethod[] = [];
if (isNotEmpty(status.authMethods)) {
authMethods = status.authMethods;
}
@@ -241,7 +239,7 @@ export class AuthService {
// Send a request that sign end the session
let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'application/x-www-form-urlencoded');
const options: HttpOptions = Object.create({headers, responseType: 'text'});
const options: HttpOptions = Object.create({ headers, responseType: 'text' });
return this.authRequestService.getRequest('logout', options).pipe(
map((status: AuthStatus) => {
if (!status.authenticated) {
@@ -317,7 +315,7 @@ export class AuthService {
// Set the cookie expire date
const expires = new Date(expireDate);
const options: CookieAttributes = {expires: expires};
const options: CookieAttributes = { expires: expires };
// Save cookie with the token
return this.storage.set(TOKENITEM, token, options);
@@ -384,7 +382,6 @@ export class AuthService {
// For standalone login pages, use the previous route.
redirUrl = history[history.length - 2] || '';
} else {
// console.log('isStandAlonePage: ', isStandalonePage);
redirUrl = history[history.length - 1] || '';
}
this.navigateToRedirectUrl(redirUrl);
@@ -438,7 +435,7 @@ export class AuthService {
// Set the cookie expire date
const expires = new Date(expireDate);
const options: CookieAttributes = {expires: expires};
const options: CookieAttributes = { expires: expires };
this.storage.set(REDIRECT_COOKIE, url, options);
this.store.dispatch(new SetRedirectUrlAction(isNotUndefined(url) ? url : ''));
}

View File

@@ -5,7 +5,7 @@ import { RemoteData } from '../../data/remote-data';
import { Observable } from 'rxjs';
import { CacheableObject } from '../../cache/object-cache.reducer';
import { ResourceType } from '../../shared/resource-type';
import {AuthMethodModel} from './auth-method.model';
import { AuthMethod } from './auth.method';
/**
* Object that represents the authenticated status of a user
@@ -56,6 +56,6 @@ export class AuthStatus implements CacheableObject {
/**
* All authentication methods enabled at the backend
*/
authMethods: AuthMethodModel[];
authMethods: AuthMethod[];
}

View File

@@ -1,6 +1,6 @@
import { AuthMethodType } from '../../../shared/log-in/methods/authMethods-type';
import { AuthMethodType } from './auth.method-type';
export class AuthMethodModel {
export class AuthMethod {
authMethodType: AuthMethodType;
location?: string;

View File

@@ -4,7 +4,6 @@ import { mapsTo, relationship } from '../../cache/builders/build-decorators';
import { NormalizedObject } from '../../cache/models/normalized-object.model';
import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer';
import { EPerson } from '../../eperson/models/eperson.model';
import {AuthMethodModel} from './auth-method.model';
@mapsTo(AuthStatus)
@inheritSerialization(NormalizedObject)

View File

@@ -1,16 +1,16 @@
import { filter, map, switchMap, take } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { HttpHeaders } from '@angular/common/http';
import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
import { AuthStatus } from './models/auth-status.model';
import { isNotEmpty } from '../../shared/empty.util';
import { AuthService } from './auth.service';
import { AuthTokenInfo } from './models/auth-token-info.model';
import { CheckAuthenticationTokenAction } from './auth.actions';
import { EPerson } from '../eperson/models/eperson.model';
import { AuthMethodModel } from './models/auth-method.model';
import { AuthMethod } from './models/auth.method';
/**
* The auth service.
@@ -76,7 +76,7 @@ export class ServerAuthService extends AuthService {
* Retrieve authentication methods available
* @returns {User}
*/
public retrieveAuthMethods(): Observable<AuthMethodModel[]> {
public retrieveAuthMethods(): Observable<AuthMethod[]> {
const options: HttpOptions = Object.create({});
if (isNotEmpty(this.req.headers) && isNotEmpty(this.req.headers.referer)) {
let headers = new HttpHeaders();
@@ -86,7 +86,7 @@ export class ServerAuthService extends AuthService {
return this.authRequestService.postToEndpoint('login', {}, options).pipe(
map((status: AuthStatus) => {
let authMethods: AuthMethodModel[];
let authMethods: AuthMethod[];
if (isNotEmpty(status.authMethods)) {
authMethods = status.authMethods;
}

View File

@@ -0,0 +1,108 @@
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { StoreModule } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { LogInContainerComponent } from './log-in-container.component';
import { authReducer } from '../../../core/auth/auth.reducer';
import { SharedModule } from '../../shared.module';
import { createTestComponent } from '../../testing/utils';
import { AuthService } from '../../../core/auth/auth.service';
import { AuthMethod } from '../../../core/auth/models/auth.method';
import { AuthServiceStub } from '../../testing/auth-service-stub';
describe('LogInContainerComponent', () => {
let component: LogInContainerComponent;
let fixture: ComponentFixture<LogInContainerComponent>;
const authMethod = new AuthMethod('password');
beforeEach(async(() => {
// refine the test module by declaring the test component
TestBed.configureTestingModule({
imports: [
FormsModule,
ReactiveFormsModule,
StoreModule.forRoot(authReducer),
SharedModule,
TranslateModule.forRoot()
],
declarations: [
TestComponent
],
providers: [
{provide: AuthService, useClass: AuthServiceStub},
LogInContainerComponent
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
})
.compileComponents();
}));
describe('', () => {
let testComp: TestComponent;
let testFixture: ComponentFixture<TestComponent>;
// synchronous beforeEach
beforeEach(() => {
const html = `<ds-log-in-container [authMethod]="authMethod"> </ds-log-in-container>`;
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
testComp = testFixture.componentInstance;
});
afterEach(() => {
testFixture.destroy();
});
it('should create LogInContainerComponent', inject([LogInContainerComponent], (app: LogInContainerComponent) => {
expect(app).toBeDefined();
}));
});
describe('', () => {
beforeEach(() => {
fixture = TestBed.createComponent(LogInContainerComponent);
component = fixture.componentInstance;
spyOn(component, 'getAuthMethodContent').and.callThrough();
component.authMethod = authMethod;
fixture.detectChanges();
});
afterEach(() => {
fixture.destroy();
component = null;
});
it('should inject component properly', () => {
component.ngOnInit();
fixture.detectChanges();
expect(component.getAuthMethodContent).toHaveBeenCalled();
});
});
});
// declare a test component
@Component({
selector: 'ds-test-cmp',
template: ``
})
class TestComponent {
isStandalonePage = true;
}

View File

@@ -0,0 +1,51 @@
import { Component, Injector, Input, OnInit } from '@angular/core';
import { rendersAuthMethodType } from '../methods/log-in.methods-decorator';
import { AuthMethod } from '../../../core/auth/models/auth.method';
/**
* This component represents a component container for log-in methods available.
*/
@Component({
selector: 'ds-log-in-container',
templateUrl: './log-in-container.component.html',
styleUrls: ['./log-in-container.component.scss']
})
export class LogInContainerComponent implements OnInit {
@Input() authMethod: AuthMethod;
/**
* Injector to inject a section component with the @Input parameters
* @type {Injector}
*/
public objectInjector: Injector;
/**
* Initialize instance variables
*
* @param {Injector} injector
*/
constructor(private injector: Injector) {
}
/**
* Initialize all instance variables
*/
ngOnInit() {
this.objectInjector = Injector.create({
providers: [
{ provide: 'authMethodProvider', useFactory: () => (this.authMethod), deps: [] },
],
parent: this.injector
});
}
/**
* Find the correct component based on the AuthMethod's type
*/
getAuthMethodContent(): string {
return rendersAuthMethodType(this.authMethod.authMethodType)
}
}

View File

@@ -1,52 +0,0 @@
import { Component, Injector, Input, OnInit} from '@angular/core';
import { rendersAuthMethodType } from '../methods/authMethods-decorator';
import { Store } from '@ngrx/store';
import { CoreState } from '../../../core/core.reducers';
import { AuthMethodModel } from '../../../core/auth/models/auth-method.model';
/**
* This component represents a section that contains the submission license form.
*/
@Component({
selector: 'ds-login-container',
templateUrl: './login-container.component.html',
styleUrls: ['./login-container.component.scss']
})
export class LoginContainerComponent implements OnInit {
@Input() authMethodModel: AuthMethodModel;
/**
* Injector to inject a section component with the @Input parameters
* @type {Injector}
*/
public objectInjector: Injector;
/**
* Initialize instance variables
*
* @param {Injector} injector
*/
constructor(private injector: Injector, private store: Store<CoreState>) {
}
/**
* Initialize all instance variables
*/
ngOnInit() {
this.objectInjector = Injector.create({
providers: [
{provide: 'authMethodModelProvider', useFactory: () => (this.authMethodModel), deps: []},
],
parent: this.injector
});
}
/**
* Find the correct component based on the AuthMethod's type
*/
getAuthMethodContent(): string {
return rendersAuthMethodType(this.authMethodModel.authMethodType)
}
}

View File

@@ -1,10 +1,10 @@
<ds-loading *ngIf="(loading | async) || (isAuthenticated | async)" class="m-5"></ds-loading>
<div *ngIf="!(loading | async) && !(isAuthenticated | async)" class="form-login px-4 py-3">
<ng-container *ngFor="let authMethodModel of (authMethodModels | async); let i = index">
<div *ngIf="!(loading | async) && !(isAuthenticated | async)" class="px-4 py-3">
<ng-container *ngFor="let authMethod of (authMethods | async); let i = index">
<div *ngIf="i === 1" class="text-center mt-2">
<span class="align-middle">{{"login.form.or-divider" | translate}}</span>
</div>
<ds-login-container [authMethodModel]="authMethodModel"></ds-login-container>
<ds-log-in-container [authMethod]="authMethod"></ds-log-in-container>
</ng-container>
<div class="dropdown-divider"></div>

View File

@@ -1,35 +1,23 @@
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { Store, StoreModule } from '@ngrx/store';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { of as observableOf } from 'rxjs';
import { StoreModule } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { LogInComponent } from './log-in.component';
import { authReducer } from '../../core/auth/auth.reducer';
import { EPersonMock } from '../testing/eperson-mock';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from '../../core/auth/auth.service';
import { AuthServiceStub } from '../testing/auth-service-stub';
import { AppState } from '../../app.reducer';
import { authMethodsMock, AuthServiceStub } from '../testing/auth-service-stub';
import { createTestComponent } from '../testing/utils';
import { SharedModule } from '../shared.module';
describe('LogInComponent', () => {
let component: LogInComponent;
let fixture: ComponentFixture<LogInComponent>;
let page: Page;
let user: EPerson;
const authState = {
authenticated: false,
loaded: false,
loading: false,
};
beforeEach(() => {
user = EPersonMock;
});
beforeEach(async(() => {
// refine the test module by declaring the test component
@@ -38,13 +26,15 @@ describe('LogInComponent', () => {
FormsModule,
ReactiveFormsModule,
StoreModule.forRoot(authReducer),
SharedModule,
TranslateModule.forRoot()
],
declarations: [
LogInComponent
TestComponent
],
providers: [
{provide: AuthService, useClass: AuthServiceStub}
{provide: AuthService, useClass: AuthServiceStub},
LogInComponent
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
@@ -54,75 +44,64 @@ describe('LogInComponent', () => {
}));
beforeEach(inject([Store], (store: Store<AppState>) => {
store
.subscribe((state) => {
(state as any).core = Object.create({});
(state as any).core.auth = authState;
});
describe('', () => {
let testComp: TestComponent;
let testFixture: ComponentFixture<TestComponent>;
// create component and test fixture
fixture = TestBed.createComponent(LogInComponent);
// synchronous beforeEach
beforeEach(() => {
const html = `<ds-log-in [isStandalonePage]="isStandalonePage"> </ds-log-in>`;
// get test component from the fixture
component = fixture.componentInstance;
// create page
page = new Page(component, fixture);
// verify the fixture is stable (no pending tasks)
fixture.whenStable().then(() => {
page.addPageElements();
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
testComp = testFixture.componentInstance;
});
}));
afterEach(() => {
testFixture.destroy();
});
/* it('should create a FormGroup comprised of FormControls', () => {
fixture.detectChanges();
expect(component.form instanceof FormGroup).toBe(true);
});*/
it('should create LogInComponent', inject([LogInComponent], (app: LogInComponent) => {
/* it('should authenticate', () => {
fixture.detectChanges();
expect(app).toBeDefined();
// set FormControl values
component.form.controls.email.setValue('user');
component.form.controls.password.setValue('password');
}));
});
// submit form
component.submit();
describe('', () => {
beforeEach(() => {
fixture = TestBed.createComponent(LogInComponent);
component = fixture.componentInstance;
component.isAuthenticated = observableOf(false);
component.loading = observableOf(false);
// verify Store.dispatch() is invoked
expect(page.navigateSpy.calls.any()).toBe(true, 'Store.dispatch not invoked');
});*/
fixture.detectChanges();
});
afterEach(() => {
fixture.destroy();
component = null;
});
it('should render a log-in container component foe each auth method available', () => {
component.authMethods = observableOf(authMethodsMock);
fixture.detectChanges();
const loginContainers = fixture.debugElement.queryAll(By.css('ds-log-in-container'));
expect(loginContainers.length).toBe(2);
});
});
});
/**
* I represent the DOM elements and attach spies.
*
* @class Page
*/
class Page {
// declare a test component
@Component({
selector: 'ds-test-cmp',
template: ``
})
class TestComponent {
public emailInput: HTMLInputElement;
public navigateSpy: jasmine.Spy;
public passwordInput: HTMLInputElement;
isStandalonePage = true;
constructor(private component: LogInComponent, private fixture: ComponentFixture<LogInComponent>) {
// use injector to get services
const injector = fixture.debugElement.injector;
const store = injector.get(Store);
// add spies
this.navigateSpy = spyOn(store, 'dispatch');
}
public addPageElements() {
const emailInputSelector = 'input[formcontrolname=\'email\']';
this.emailInput = this.fixture.debugElement.query(By.css(emailInputSelector)).nativeElement;
const passwordInputSelector = 'input[formcontrolname=\'password\']';
this.passwordInput = this.fixture.debugElement.query(By.css(passwordInputSelector)).nativeElement;
}
}

View File

@@ -1,26 +1,37 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { AuthMethodModel } from '../../core/auth/models/auth-method.model';
import { filter, takeWhile, } from 'rxjs/operators';
import { select, Store } from '@ngrx/store';
import { AuthMethod } from '../../core/auth/models/auth.method';
import { getAuthenticationMethods, isAuthenticated, isAuthenticationLoading } from '../../core/auth/selectors';
import { CoreState } from '../../core/core.reducers';
import { filter, takeWhile, } from 'rxjs/operators';
import { AuthService } from '../../core/auth/auth.service';
/**
* /users/sign-in
* @class LogInComponent
*/
@Component({
selector: 'ds-log-in',
templateUrl: './log-in.component.html',
styleUrls: ['./log-in.component.scss']
})
export class LogInComponent implements OnInit, OnDestroy {
/**
* The authentication methods data
* @type {AuthMethodModel[]}
*/
@Input() authMethodModels: Observable<AuthMethodModel[]>;
/**
* A boolean representing if LogInComponent is in a standalone page
* @type {boolean}
*/
@Input() isStandalonePage: boolean;
/**
* The list of authentication methods available
* @type {AuthMethod[]}
*/
public authMethods: Observable<AuthMethod[]>;
/**
* Whether user is authenticated.
* @type {Observable<string>}
@@ -45,9 +56,7 @@ export class LogInComponent implements OnInit, OnDestroy {
ngOnInit(): void {
// this.store.dispatch(new SetIsStandalonePageInAuthMethodsAction(this.isStandalonePage));
this.authMethodModels = this.store.pipe(
this.authMethods = this.store.pipe(
select(getAuthenticationMethods),
);

View File

@@ -1,4 +1,4 @@
import { AuthMethodType } from './authMethods-type';
import { AuthMethodType } from '../../../core/auth/models/auth.method-type';
const authMethodsMap = new Map();

View File

@@ -4,16 +4,17 @@ import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { Store, StoreModule } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { LogInPasswordComponent } from './log-in-password.component';
import { EPerson } from '../../../../core/eperson/models/eperson.model';
import { EPersonMock } from '../../../testing/eperson-mock';
import { authReducer } from '../../../../core/auth/auth.reducer';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from '../../../../core/auth/auth.service';
import { AuthServiceStub } from '../../../testing/auth-service-stub';
import { AppState } from '../../../../app.reducer';
import { AuthMethodModel } from '../../../../core/auth/models/auth-method.model';
import { AuthMethodType } from '../authMethods-type';
import { AuthMethod } from '../../../../core/auth/models/auth.method';
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
describe('LogInPasswordComponent', () => {
@@ -46,7 +47,7 @@ describe('LogInPasswordComponent', () => {
],
providers: [
{ provide: AuthService, useClass: AuthServiceStub },
{ provide: 'authMethodModelProvider', useValue: new AuthMethodModel(AuthMethodType.Password) }
{ provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Password) }
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA

View File

@@ -1,5 +1,5 @@
import { map } from 'rxjs/operators';
import { Component, Inject, Input, OnInit } from '@angular/core';
import { Component, Inject, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { select, Store } from '@ngrx/store';
@@ -8,12 +8,11 @@ import { AuthenticateAction, ResetAuthenticationMessagesAction } from '../../../
import { getAuthenticationError, getAuthenticationInfo, } from '../../../../core/auth/selectors';
import { CoreState } from '../../../../core/core.reducers';
import { isNotEmpty } from '../../../empty.util';
import { fadeOut } from '../../../animations/fade';
import { AuthMethodType } from '../authMethods-type';
import { renderAuthMethodFor } from '../authMethods-decorator';
import { AuthMethodModel } from '../../../../core/auth/models/auth-method.model';
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
import { renderAuthMethodFor } from '../log-in.methods-decorator';
import { AuthMethod } from '../../../../core/auth/models/auth.method';
/**
* /users/sign-in
@@ -28,6 +27,12 @@ import { AuthMethodModel } from '../../../../core/auth/models/auth-method.model'
@renderAuthMethodFor(AuthMethodType.Password)
export class LogInPasswordComponent implements OnInit {
/**
* The authentication method data.
* @type {AuthMethod}
*/
public authMethod: AuthMethod;
/**
* The error if authentication fails.
* @type {Observable<string>}
@@ -58,21 +63,18 @@ export class LogInPasswordComponent implements OnInit {
*/
public form: FormGroup;
@Input() authMethodModel: AuthMethodModel;
/**
* @constructor
* @param {AuthMethodModel} injectedAuthMethodModel
* @param {AuthMethod} injectedAuthMethodModel
* @param {FormBuilder} formBuilder
* @param {Store<State>} store
*/
constructor(
@Inject('authMethodModelProvider') public injectedAuthMethodModel: AuthMethodModel,
/* private authService: AuthService,*/
@Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod,
private formBuilder: FormBuilder,
private store: Store<CoreState>
) {
this.authMethodModel = injectedAuthMethodModel;
this.authMethod = injectedAuthMethodModel;
}
/**
@@ -118,15 +120,6 @@ export class LogInPasswordComponent implements OnInit {
}
}
/**
* To the registration page.
* @method register
*/
public register() {
// TODO enable after registration process is done
// this.router.navigate(['/register']);
}
/**
* Submit the authentication form.
* @method submit

View File

@@ -0,0 +1,105 @@
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Store, StoreModule } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { EPerson } from '../../../../core/eperson/models/eperson.model';
import { EPersonMock } from '../../../testing/eperson-mock';
import { authReducer } from '../../../../core/auth/auth.reducer';
import { AuthService } from '../../../../core/auth/auth.service';
import { AuthServiceStub } from '../../../testing/auth-service-stub';
import { AppState } from '../../../../app.reducer';
import { AuthMethod } from '../../../../core/auth/models/auth.method';
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
import { LogInShibbolethComponent } from './log-in-shibboleth.component';
describe('LogInShibbolethComponent', () => {
let component: LogInShibbolethComponent;
let fixture: ComponentFixture<LogInShibbolethComponent>;
let page: Page;
let user: EPerson;
const authState = {
authenticated: false,
loaded: false,
loading: false,
};
beforeEach(() => {
user = EPersonMock;
});
beforeEach(async(() => {
// refine the test module by declaring the test component
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot(authReducer),
TranslateModule.forRoot()
],
declarations: [
LogInShibbolethComponent
],
providers: [
{ provide: AuthService, useClass: AuthServiceStub },
{ provide: 'authMethodProvider',
useValue: new AuthMethod(AuthMethodType.Shibboleth, 'dspace.test/shibboleth')
}
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
})
.compileComponents();
}));
beforeEach(inject([Store], (store: Store<AppState>) => {
store
.subscribe((state) => {
(state as any).core = Object.create({});
(state as any).core.auth = authState;
});
// create component and test fixture
fixture = TestBed.createComponent(LogInShibbolethComponent);
// get test component from the fixture
component = fixture.componentInstance;
// create page
page = new Page(component, fixture);
}));
it('should display a link with properly href', () => {
fixture.detectChanges();
const link = fixture.debugElement.query(By.css('a'));
expect(link.nativeElement.getAttribute('href')).toBe('dspace.test/shibboleth');
});
});
/**
* I represent the DOM elements and attach spies.
*
* @class Page
*/
class Page {
public emailInput: HTMLInputElement;
public navigateSpy: jasmine.Spy;
public passwordInput: HTMLInputElement;
constructor(private component: LogInShibbolethComponent, private fixture: ComponentFixture<LogInShibbolethComponent>) {
// use injector to get services
const injector = fixture.debugElement.injector;
const store = injector.get(Store);
// add spies
this.navigateSpy = spyOn(store, 'dispatch');
}
}

View File

@@ -1,11 +1,11 @@
import { Component, Inject, Input, OnInit, } from '@angular/core';
import { Component, Inject, OnInit, } from '@angular/core';
import { Observable } from 'rxjs';
import { select, Store } from '@ngrx/store';
import { renderAuthMethodFor } from '../authMethods-decorator';
import { AuthMethodType } from '../authMethods-type';
import { AuthMethodModel } from '../../../../core/auth/models/auth-method.model';
import { renderAuthMethodFor } from '../log-in.methods-decorator';
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
import { AuthMethod } from '../../../../core/auth/models/auth.method';
import { CoreState } from '../../../../core/core.reducers';
import { isAuthenticated, isAuthenticationLoading } from '../../../../core/auth/selectors';
@@ -19,7 +19,11 @@ import { isAuthenticated, isAuthenticationLoading } from '../../../../core/auth/
@renderAuthMethodFor(AuthMethodType.Shibboleth)
export class LogInShibbolethComponent implements OnInit {
@Input() authMethodModel: AuthMethodModel;
/**
* The authentication method data.
* @type {AuthMethod}
*/
public authMethod: AuthMethod;
/**
* True if the authentication is loading.
@@ -41,12 +45,14 @@ export class LogInShibbolethComponent implements OnInit {
/**
* @constructor
* @param {AuthMethod} injectedAuthMethodModel
* @param {Store<State>} store
*/
constructor(
@Inject('authMethodModelProvider') public injectedAuthMethodModel: AuthMethodModel,
@Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod,
private store: Store<CoreState>
) {
this.authMethodModel = injectedAuthMethodModel;
this.authMethod = injectedAuthMethodModel;
}
ngOnInit(): void {

View File

@@ -171,9 +171,8 @@ import { PageWithSidebarComponent } from './sidebar/page-with-sidebar.component'
import { SidebarDropdownComponent } from './sidebar/sidebar-dropdown.component';
import { SidebarFilterComponent } from './sidebar/filter/sidebar-filter.component';
import { SidebarFilterSelectedOptionComponent } from './sidebar/filter/sidebar-filter-selected-option.component';
import { MetadataRepresentationListComponent } from '../+item-page/simple/metadata-representation-list/metadata-representation-list.component';
import { SelectableListItemControlComponent } from './object-collection/shared/selectable-list-item-control/selectable-list-item-control.component';
import { LoginContainerComponent } from './log-in/container/login-container.component';
import { LogInContainerComponent } from './log-in/container/log-in-container.component';
import { LogInShibbolethComponent } from './log-in/methods/shibboleth/log-in-shibboleth.component';
import { LogInPasswordComponent } from './log-in/methods/password/log-in-password.component';
import { LogInComponent } from './log-in/log-in.component';
@@ -336,7 +335,7 @@ const COMPONENTS = [
SelectableListItemControlComponent,
LogInShibbolethComponent,
LogInPasswordComponent,
LoginContainerComponent,
LogInContainerComponent,
ItemTypeBadgeComponent
];

View File

@@ -5,7 +5,6 @@ import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { isNotEmpty } from '../empty.util';
import { EPersonMock } from './eperson-mock';
import { RemoteData } from '../../core/data/remote-data';
import { createSuccessfulRemoteDataObject$ } from './utils';
export class AuthRequestServiceStub {
@@ -23,7 +22,7 @@ export class AuthRequestServiceStub {
} else {
authStatusStub.authenticated = false;
}
} else {
} else if (isNotEmpty(options)) {
const token = (options.headers as any).lazyUpdate[1].value;
if (this.validateToken(token)) {
authStatusStub.authenticated = true;
@@ -32,6 +31,8 @@ export class AuthRequestServiceStub {
} else {
authStatusStub.authenticated = false;
}
} else {
authStatusStub.authenticated = false;
}
return observableOf(authStatusStub);
}

View File

@@ -3,8 +3,13 @@ import { AuthStatus } from '../../core/auth/models/auth-status.model';
import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
import { EPersonMock } from './eperson-mock';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { RemoteData } from '../../core/data/remote-data';
import { createSuccessfulRemoteDataObject$ } from './utils';
import { AuthMethod } from '../../core/auth/models/auth.method';
export const authMethodsMock = [
new AuthMethod('password'),
new AuthMethod('shibboleth', 'dspace.test/shibboleth')
];
export class AuthServiceStub {
@@ -103,4 +108,12 @@ export class AuthServiceStub {
isAuthenticated() {
return observableOf(true);
}
checkAuthenticationCookie() {
return;
}
retrieveAuthMethods(status: AuthStatus) {
return observableOf(authMethodsMock);
}
}