diff --git a/src/app/core/auth/auth.interceptor.ts b/src/app/core/auth/auth.interceptor.ts index 215d646dfd..015ed1a02d 100644 --- a/src/app/core/auth/auth.interceptor.ts +++ b/src/app/core/auth/auth.interceptor.ts @@ -85,6 +85,15 @@ export class AuthInterceptor implements HttpInterceptor { return http.url && http.url.endsWith('/authn/logout'); } + /** + * Check if response is from a status request + * + * @param http + */ + private isStatusResponse(http: HttpRequest | HttpResponseBase): boolean { + return http.url && http.url.endsWith('/authn/status'); + } + /** * Extract location url from the WWW-Authenticate header * @@ -202,8 +211,10 @@ export class AuthInterceptor implements HttpInterceptor { const authService = this.inj.get(AuthService); - const token = authService.getToken(); - let newReq; + const token: AuthTokenInfo = authService.getToken(); + let newReq: HttpRequest; + let updateReq: any = {}; + let authorization: string; if (authService.isTokenExpired()) { authService.setRedirectUrl(this.router.url); @@ -224,11 +235,13 @@ export class AuthInterceptor implements HttpInterceptor { } }); // Get the auth header from the service. - const Authorization = authService.buildAuthHeader(token); + authorization = authService.buildAuthHeader(token); // Clone the request to add the new header. - newReq = req.clone({headers: req.headers.set('authorization', Authorization)}); + newReq = req.clone({ headers: req.headers.set('authorization', authorization) }); } else { - const updateReq = this.isAuthRequest(req) ? { withCredentials: true } : {}; + if (this.isAuthRequest(req)) { + updateReq = { withCredentials: true }; + } newReq = req.clone(updateReq); } @@ -237,19 +250,29 @@ export class AuthInterceptor implements HttpInterceptor { // tap((response) => console.log('next.handle: ', response)), map((response) => { // Intercept a Login/Logout response - if (response instanceof HttpResponse && this.isSuccess(response) && (this.isLoginResponse(response) || this.isLogoutResponse(response))) { + if (response instanceof HttpResponse && this.isSuccess(response) && this.isAuthRequest(response)) { // It's a success Login/Logout response let authRes: HttpResponse; if (this.isLoginResponse(response)) { // login successfully const newToken = response.headers.get('authorization'); - authRes = response.clone({body: this.makeAuthStatusObject(true, newToken)}); + authRes = response.clone({ + body: this.makeAuthStatusObject(true, newToken) + }); // clean eventually refresh Requests list this.refreshTokenRequestUrls = []; + } else if (this.isStatusResponse(response)) { + authRes = response.clone({ + body: Object.assign(response.body, { + authMethods: this.parseAuthMethodsFromHeaders(response.headers) + }) + }) } else { // logout successfully - authRes = response.clone({body: this.makeAuthStatusObject(false)}); + authRes = response.clone({ + body: this.makeAuthStatusObject(false) + }); } return authRes; } else { diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 7026039692..0978cc3084 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -16,7 +16,13 @@ import { AuthStatus } from './models/auth-status.model'; import { AuthTokenInfo, TOKENITEM } from './models/auth-token-info.model'; import { isEmpty, isNotEmpty, isNotNull, isNotUndefined } from '../../shared/empty.util'; import { CookieService } from '../services/cookie.service'; -import { getAuthenticationToken, getRedirectUrl, isAuthenticated, isTokenRefreshing } from './selectors'; +import { + getAuthenticationMethods, + getAuthenticationToken, + getRedirectUrl, + isAuthenticated, + isTokenRefreshing +} from './selectors'; import { AppState, routerStateSelector } from '../../app.reducer'; import { CheckAuthenticationTokenAction, @@ -28,6 +34,7 @@ import { Base64EncodeUrl } from '../../shared/utils/encode-decode.util'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { RouteService } from '../services/route.service'; import { AuthMethod } from './models/auth.method'; +import { NormalizedAuthStatus } from './models/normalized-auth-status.model'; export const LOGIN_ROUTE = '/login'; export const LOGOUT_ROUTE = '/logout'; @@ -121,7 +128,14 @@ export class AuthService { * Checks if token is present into the request cookie */ public checkAuthenticationCookie(): Observable { - return this.authRequestService.postToEndpoint('login'); + // Determine if the user has an existing auth session on the server + const options: HttpOptions = Object.create({}); + let headers = new HttpHeaders(); + headers = headers.append('Accept', 'application/json'); + options.headers = headers; + return this.authRequestService.getRequest('status', options).pipe( + map((status: NormalizedAuthStatus) => Object.assign(new AuthStatus(), status)) + ); } /** @@ -158,7 +172,13 @@ export class AuthService { * Checks if token is present into browser storage and is valid. (NB Check is done only on SSR) */ public checkAuthenticationToken() { - this.store.dispatch(new CheckAuthenticationTokenAction()); + this.store.pipe( + select(getAuthenticationMethods), + filter((authMethods: AuthMethod[]) => isEmpty(authMethods)), + take(1) + ).subscribe(() => { + this.store.dispatch(new CheckAuthenticationTokenAction()); + }); } /** diff --git a/src/app/core/auth/models/normalized-auth-status.model.ts b/src/app/core/auth/models/normalized-auth-status.model.ts index d8d0c0b952..6af98bb22f 100644 --- a/src/app/core/auth/models/normalized-auth-status.model.ts +++ b/src/app/core/auth/models/normalized-auth-status.model.ts @@ -4,6 +4,7 @@ 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 { AuthMethod } from './auth.method'; @mapsTo(AuthStatus) @inheritSerialization(NormalizedObject) @@ -39,4 +40,9 @@ export class NormalizedAuthStatus extends NormalizedObject { @autoserialize eperson: string; + /** + * All authentication methods enabled at the backend + */ + @autoserialize + authMethods: AuthMethod[]; } diff --git a/src/app/core/data/request.models.ts b/src/app/core/data/request.models.ts index ca864f99de..5b3a6cde19 100644 --- a/src/app/core/data/request.models.ts +++ b/src/app/core/data/request.models.ts @@ -225,6 +225,8 @@ export class AuthPostRequest extends PostRequest { } export class AuthGetRequest extends GetRequest { + forceBypassCache = true; + constructor(uuid: string, href: string, public options?: HttpOptions) { super(uuid, href, null, options); }