Skip to content

Commit dcd6971

Browse files
committed
fix: correctly handle MFA timeout
* If the MfaTimeoutError is thrown by backend, then we should force new authentication included first factor and second factor
1 parent 358c22e commit dcd6971

File tree

3 files changed

+21
-5
lines changed

3 files changed

+21
-5
lines changed

libs/perun/services/src/lib/ApiInterceptor.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,12 @@ export class ApiInterceptor implements HttpInterceptor {
126126
catchError((err: HttpErrorResponse) => {
127127
const e = err.error as RPCError;
128128
// catch MFA required error and start MFA logic
129-
if (e.type === 'MfaPrivilegeException' || e.type === 'MfaRolePrivilegeException') {
130-
return this.mfaHandlerService.openMfaWindow(e.type === 'MfaRolePrivilegeException').pipe(
129+
if (
130+
e.type === 'MfaPrivilegeException' ||
131+
e.type === 'MfaRolePrivilegeException' ||
132+
e.type === 'MfaTimeoutException'
133+
) {
134+
return this.mfaHandlerService.openMfaWindow(e.type).pipe(
131135
switchMap((verified) => {
132136
if (verified) {
133137
if (e.type === 'MfaRolePrivilegeException') {

libs/perun/services/src/lib/auth.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ export class AuthService {
114114
if (sessionStorage.getItem('mfa_route') || localStorage.getItem('mfaProcessed')) {
115115
customQueryParams['acr_values'] = 'https://refeds.org/profile/mfa';
116116
}
117-
if (sessionStorage.getItem('mfa_route')) {
117+
if (sessionStorage.getItem('mfa_route') || localStorage.getItem('mfaTimeout')) {
118+
// mfaTimeout = force new authentication if mfaTimeoutError is thrown by Perun
118119
if (customQueryParams['prompt']) {
119120
customQueryParams['prompt'] += ' login';
120121
} else {

libs/perun/services/src/lib/mfa-handler.service.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ import { OAuthService } from 'angular-oauth2-oidc';
1111
import { AuthService } from './auth.service';
1212
import { StoreService } from './store.service';
1313

14+
export type MfaExceptionType =
15+
| 'MfaPrivilegeException'
16+
| 'MfaRolePrivilegeException'
17+
| 'MfaTimeoutException';
18+
1419
@Injectable({
1520
providedIn: 'root',
1621
})
@@ -30,20 +35,24 @@ export class MfaHandlerService {
3035
* opened another window and the user cannot continue in the original application
3136
* without finishing authentication/closing the second window
3237
*/
33-
openMfaWindow(mfaRoleException: boolean): Observable<boolean> {
38+
openMfaWindow(mfaExceptionType: MfaExceptionType): Observable<boolean> {
3439
let newWindow: Window = null;
3540
let dialogRef: MatDialogRef<FocusOnMfaWindowComponent, void> = null;
3641

3742
const configVerify = getDefaultDialogConfig();
3843
configVerify.width = '450px';
3944
configVerify.data = {
40-
mfaRoleException: mfaRoleException,
45+
mfaRoleException: mfaExceptionType === 'MfaRolePrivilegeException',
4146
};
4247
const dialogVerifyRef = this.dialog.open(MfaRequiredDialogComponent, configVerify);
4348
let verificationSkipped = false;
4449

4550
dialogVerifyRef.afterClosed().subscribe((result) => {
4651
if (result) {
52+
if (mfaExceptionType === 'MfaTimeoutException') {
53+
localStorage.setItem('mfaTimeout', 'true');
54+
}
55+
4756
localStorage.setItem('mfaRequired', 'true');
4857

4958
// save tokens - if MFA will NOT be successful, we will need to give them back to oauth storage
@@ -82,6 +91,7 @@ export class MfaHandlerService {
8291
dialogRef.close();
8392
localStorage.removeItem('mfaRequired');
8493
localStorage.removeItem('mfaProcessed');
94+
localStorage.removeItem('mfaTimeout');
8595
// if the window is closed without successful MFA, then give back previous tokens to the oauth storage
8696
if (this.oauthService.getAccessToken() === null) {
8797
localStorage.setItem('access_token', sessionStorage.getItem('oldAccessToken'));
@@ -132,6 +142,7 @@ export class MfaHandlerService {
132142
closeMfaWindow(): void {
133143
if (localStorage.getItem('mfaProcessed') && !localStorage.getItem('mfaRequired')) {
134144
localStorage.removeItem('mfaProcessed');
145+
localStorage.removeItem('mfaTimeout');
135146
window.close();
136147
}
137148
}

0 commit comments

Comments
 (0)