Skip to content

Commit 290a899

Browse files
committed
Added check for external auth and page refresh
1 parent ade9533 commit 290a899

9 files changed

Lines changed: 104 additions & 4 deletions

File tree

src/app/core/auth/auth.actions.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const AuthActionTypes = {
1717
AUTHENTICATED_SUCCESS: type('dspace/auth/AUTHENTICATED_SUCCESS'),
1818
CHECK_AUTHENTICATION_TOKEN: type('dspace/auth/CHECK_AUTHENTICATION_TOKEN'),
1919
CHECK_AUTHENTICATION_TOKEN_COOKIE: type('dspace/auth/CHECK_AUTHENTICATION_TOKEN_COOKIE'),
20+
SET_AUTH_COOKIE_STATUS: type('dspace/auth/SET_AUTH_COOKIE_STATUS'),
2021
RETRIEVE_AUTH_METHODS: type('dspace/auth/RETRIEVE_AUTH_METHODS'),
2122
RETRIEVE_AUTH_METHODS_SUCCESS: type('dspace/auth/RETRIEVE_AUTH_METHODS_SUCCESS'),
2223
RETRIEVE_AUTH_METHODS_ERROR: type('dspace/auth/RETRIEVE_AUTH_METHODS_ERROR'),
@@ -150,6 +151,19 @@ export class CheckAuthenticationTokenCookieAction implements Action {
150151
public type: string = AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE;
151152
}
152153

154+
/**
155+
* Sets the authentication cookie status to flag an external authentication response.
156+
*/
157+
export class SetAuthCookieStatus implements Action {
158+
public type: string = AuthActionTypes.SET_AUTH_COOKIE_STATUS;
159+
160+
payload = false;
161+
162+
constructor(exists: boolean) {
163+
this.payload = exists;
164+
}
165+
}
166+
153167
/**
154168
* Sign out.
155169
* @class LogOutAction
@@ -425,6 +439,7 @@ export type AuthActions
425439
| AuthenticationSuccessAction
426440
| CheckAuthenticationTokenAction
427441
| CheckAuthenticationTokenCookieAction
442+
| SetAuthCookieStatus
428443
| RedirectWhenAuthenticationIsRequiredAction
429444
| RedirectWhenTokenExpiredAction
430445
| AddAuthenticationMessageAction

src/app/core/auth/auth.effects.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,14 @@ describe('AuthEffects', () => {
214214
authenticated: true
215215
})
216216
);
217+
spyOn((authEffects as any).authService, 'setExternalAuthStatus');
217218
actions = hot('--a-', { a: { type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE } });
218219

219220
const expected = cold('--b-', { b: new RetrieveTokenAction() });
220221

221222
expect(authEffects.checkTokenCookie$).toBeObservable(expected);
222223
authEffects.checkTokenCookie$.subscribe(() => {
224+
expect(authServiceStub.setExternalAuthStatus).toHaveBeenCalledWith(true);
223225
expect((authEffects as any).authorizationsService.invalidateAuthorizationsRequestCache).toHaveBeenCalled();
224226
});
225227
});

src/app/core/auth/auth.effects.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ export class AuthEffects {
153153
return this.authService.checkAuthenticationCookie().pipe(
154154
map((response: AuthStatus) => {
155155
if (response.authenticated) {
156+
this.authService.setExternalAuthStatus(true);
156157
this.authorizationsService.invalidateAuthorizationsRequestCache();
157158
return new RetrieveTokenAction();
158159
} else {

src/app/core/auth/auth.reducer.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
AuthenticationErrorAction,
99
AuthenticationSuccessAction,
1010
CheckAuthenticationTokenAction,
11+
SetAuthCookieStatus,
1112
CheckAuthenticationTokenCookieAction,
1213
LogOutAction,
1314
LogOutErrorAction,
@@ -219,6 +220,28 @@ describe('authReducer', () => {
219220
expect(newState).toEqual(state);
220221
});
221222

223+
it('should set the authentication cookie status in response to a SET_AUTH_COOKIE_STATUS action', () => {
224+
initialState = {
225+
authenticated: true,
226+
loaded: false,
227+
blocking: false,
228+
loading: true,
229+
externalAuth: false,
230+
idle: false
231+
};
232+
const action = new SetAuthCookieStatus(true);
233+
const newState = authReducer(initialState, action);
234+
state = {
235+
authenticated: true,
236+
loaded: false,
237+
blocking: false,
238+
loading: true,
239+
externalAuth: true,
240+
idle: false
241+
};
242+
expect(newState).toEqual(state);
243+
});
244+
222245
it('should properly set the state, in response to a LOG_OUT action', () => {
223246
initialState = {
224247
authenticated: true,

src/app/core/auth/auth.reducer.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
RedirectWhenTokenExpiredAction,
1111
RefreshTokenSuccessAction,
1212
RetrieveAuthenticatedEpersonSuccessAction,
13-
RetrieveAuthMethodsSuccessAction,
13+
RetrieveAuthMethodsSuccessAction, SetAuthCookieStatus,
1414
SetRedirectUrlAction
1515
} from './auth.actions';
1616
// import models
@@ -59,6 +59,8 @@ export interface AuthState {
5959
// all authentication Methods enabled at the backend
6060
authMethods?: AuthMethod[];
6161

62+
externalAuth?: boolean,
63+
6264
// true when the current user is idle
6365
idle: boolean;
6466

@@ -73,6 +75,7 @@ const initialState: AuthState = {
7375
blocking: true,
7476
loading: false,
7577
authMethods: [],
78+
externalAuth: false,
7679
idle: false
7780
};
7881

@@ -104,6 +107,11 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
104107
loading: true,
105108
});
106109

110+
case AuthActionTypes.SET_AUTH_COOKIE_STATUS:
111+
return Object.assign({}, state, {
112+
externalAuth: (action as SetAuthCookieStatus).payload
113+
});
114+
107115
case AuthActionTypes.AUTHENTICATED_ERROR:
108116
case AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON_ERROR:
109117
return Object.assign({}, state, {

src/app/core/auth/auth.service.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
import { CookieService } from '../services/cookie.service';
2626
import {
2727
getAuthenticatedUserId,
28-
getAuthenticationToken,
28+
getAuthenticationToken, getExternalAuthCookieStatus,
2929
getRedirectUrl,
3030
isAuthenticated,
3131
isAuthenticatedLoaded,
@@ -36,7 +36,7 @@ import { AppState } from '../../app.reducer';
3636
import {
3737
CheckAuthenticationTokenAction,
3838
RefreshTokenAction,
39-
ResetAuthenticationMessagesAction,
39+
ResetAuthenticationMessagesAction, SetAuthCookieStatus,
4040
SetRedirectUrlAction,
4141
SetUserAsIdleAction,
4242
UnsetUserAsIdleAction
@@ -156,6 +156,15 @@ export class AuthService {
156156
return this.store.pipe(select(isAuthenticatedLoaded));
157157
}
158158

159+
public setExternalAuthStatus(external: boolean) {
160+
this.store.dispatch(new SetAuthCookieStatus(external));
161+
}
162+
163+
public isExternalAuthentication(): Observable<boolean> {
164+
return this.store.pipe(
165+
select(getExternalAuthCookieStatus));
166+
}
167+
159168
/**
160169
* Returns the href link to authenticated user
161170
* @returns {string}

src/app/core/auth/selectors.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ const _getRedirectUrl = (state: AuthState) => state.redirectUrl;
116116

117117
const _getAuthenticationMethods = (state: AuthState) => state.authMethods;
118118

119+
const _getExternalAuthCookieStatus = (state: AuthState) => state.externalAuth;
120+
119121
/**
120122
* Returns true if the user is idle.
121123
* @function _isIdle
@@ -178,6 +180,16 @@ export const isAuthenticated = createSelector(getAuthState, _isAuthenticated);
178180
*/
179181
export const isAuthenticatedLoaded = createSelector(getAuthState, _isAuthenticatedLoaded);
180182

183+
/**
184+
* Returns the authentication cookie status. Expect to be ture when external authentication
185+
* is used.
186+
* @function getExternalAuthCookieStatus
187+
* @param {AuthState} state
188+
* @param {any} props
189+
* @return {boolean}
190+
*/
191+
export const getExternalAuthCookieStatus = createSelector(getAuthState, _getExternalAuthCookieStatus);
192+
181193
/**
182194
* Returns true if the authentication request is loading.
183195
* @function isAuthenticationLoading

src/app/shared/testing/auth-service.stub.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ export class AuthServiceStub {
122122
checkAuthenticationCookie() {
123123
return;
124124
}
125+
setExternalAuthStatus(externalCookie: boolean) {
126+
return;
127+
}
128+
129+
isExternalAuthentication(): Observable<boolean> {
130+
return;
131+
}
125132

126133
retrieveAuthMethodsFromAuthStatus(status: AuthStatus) {
127134
return observableOf(authMethodsMock);

src/modules/app/browser-init.service.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ import { AuthService } from '../../app/core/auth/auth.service';
2626
import { ThemeService } from '../../app/shared/theme-support/theme.service';
2727
import { StoreAction, StoreActionTypes } from '../../app/store.actions';
2828
import { coreSelector } from '../../app/core/core.selectors';
29-
import { find, map } from 'rxjs/operators';
29+
import { filter, find, map, switchMap } from 'rxjs/operators';
3030
import { isNotEmpty } from '../../app/shared/empty.util';
3131
import { logStartupMessage } from '../../../startup-message';
3232
import { MenuService } from '../../app/shared/menu/menu.service';
33+
import { RootDataService } from '../../app/core/data/root-data.service';
3334

3435
/**
3536
* Performs client-side initialization.
@@ -51,6 +52,7 @@ export class BrowserInitService extends InitService {
5152
protected authService: AuthService,
5253
protected themeService: ThemeService,
5354
protected menuService: MenuService,
55+
private rootDatatService: RootDataService
5456
) {
5557
super(
5658
store,
@@ -80,6 +82,7 @@ export class BrowserInitService extends InitService {
8082
return async () => {
8183
await this.loadAppState();
8284
this.checkAuthenticationToken();
85+
this.externalAuthCheck();
8386
this.initCorrelationId();
8487

8588
this.checkEnvironment();
@@ -134,4 +137,24 @@ export class BrowserInitService extends InitService {
134137
protected initGoogleAnalytics() {
135138
this.googleAnalyticsService.addTrackingIdToPage();
136139
}
140+
141+
/**
142+
* When authenticated during the external authentication flow invalidate
143+
* the cache so the app is rehydrated with fresh data.
144+
* @private
145+
*/
146+
private externalAuthCheck() {
147+
148+
this.authenticationReady$().pipe(
149+
switchMap(() => this.authService.isExternalAuthentication().pipe(
150+
filter((externalAuth: boolean) => externalAuth)
151+
))
152+
).subscribe(() => {
153+
this.authService.setExternalAuthStatus(false);
154+
this.rootDatatService.invalidateRootCache();
155+
}
156+
);
157+
158+
}
159+
137160
}

0 commit comments

Comments
 (0)