mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-31 17:38:48 +00:00
[AAE-12521] move navigation to the guard to fix infinite loop issue with code flow auth
This commit is contained in:
@@ -16,57 +16,90 @@
|
||||
*/
|
||||
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AuthService } from './auth.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { OidcAuthGuard } from './oidc-auth.guard';
|
||||
|
||||
const state: RouterStateSnapshot = {
|
||||
root: new ActivatedRouteSnapshot(),
|
||||
url: 'http://example.com'
|
||||
};
|
||||
const routeSnapshot = new ActivatedRouteSnapshot();
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
describe('OidcAuthGuard', () => {
|
||||
let oidcAuthGuard: OidcAuthGuard;
|
||||
let authServiceSpy: jasmine.SpyObj<AuthService>;
|
||||
let routerSpy: jasmine.SpyObj<Router>;
|
||||
|
||||
beforeEach(() => {
|
||||
const routerSpyObj = jasmine.createSpyObj('Router', ['navigateByUrl']);
|
||||
const authSpy = jasmine.createSpyObj('AuthService', ['loginCallback']);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule],
|
||||
providers: [OidcAuthGuard]
|
||||
providers: [
|
||||
OidcAuthGuard,
|
||||
{ provide: AuthService, useValue: authSpy },
|
||||
{ provide: Router, useValue: routerSpyObj }
|
||||
],
|
||||
imports: [RouterTestingModule]
|
||||
});
|
||||
|
||||
routerSpy = TestBed.inject(Router) as jasmine.SpyObj<Router>;
|
||||
oidcAuthGuard = TestBed.inject(OidcAuthGuard);
|
||||
authServiceSpy = TestBed.inject(AuthService) as jasmine.SpyObj<AuthService>;
|
||||
});
|
||||
|
||||
describe('canActivate', () => {
|
||||
it('should return true if is authenticated', () => {
|
||||
authServiceSpy.authenticated = true;
|
||||
|
||||
const result = oidcAuthGuard.canActivate();
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should call isAuthenticated and return the result', () => {
|
||||
const isAuthenticatedSpy = spyOn<any>(oidcAuthGuard, '_isAuthenticated').and.returnValue(true);
|
||||
|
||||
const result = oidcAuthGuard.canActivate();
|
||||
|
||||
expect(isAuthenticatedSpy).toHaveBeenCalled();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#canActivate', () => {
|
||||
it('should return false if the user is not authenticated, and call login method', () => {
|
||||
const authService = { authenticated: false, login: jasmine.createSpy() } as unknown as AuthService;
|
||||
const authGuard = new OidcAuthGuard(authService);
|
||||
describe('canActivateChild', () => {
|
||||
it('should call isAuthenticated and return its result', () => {
|
||||
const isAuthenticatedSpy = spyOn<any>(oidcAuthGuard, '_isAuthenticated').and.returnValue(true);
|
||||
|
||||
expect(authGuard.canActivate(routeSnapshot, state)).toEqual(false);
|
||||
expect(authService.login).toHaveBeenCalled();
|
||||
});
|
||||
const result = oidcAuthGuard.canActivateChild();
|
||||
|
||||
it('should return true if the user is authenticated', () => {
|
||||
const authService = { authenticated: true } as unknown as AuthService;
|
||||
const authGuard = new OidcAuthGuard(authService);
|
||||
|
||||
expect(authGuard.canActivate(routeSnapshot, state)).toEqual(true);
|
||||
expect(isAuthenticatedSpy).toHaveBeenCalled();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#canActivateChild', () => {
|
||||
it('should return false if the user is not authenticated, and call login method', () => {
|
||||
const authService = { authenticated: false, login: jasmine.createSpy() } as unknown as AuthService;
|
||||
const authGuard = new OidcAuthGuard(authService);
|
||||
describe('isAuthenticated', () => {
|
||||
it('should return true if is authenticated', () => {
|
||||
authServiceSpy.authenticated = true;
|
||||
|
||||
expect(authGuard.canActivateChild(routeSnapshot, state)).toEqual(false);
|
||||
expect(authService.login).toHaveBeenCalled();
|
||||
const result = oidcAuthGuard['_isAuthenticated']();
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if the user is authenticated', () => {
|
||||
const authService = { authenticated: true } as unknown as AuthService;
|
||||
const authGuard = new OidcAuthGuard(authService);
|
||||
it('should call loginCallback and navigateByUrl if not authenticated', async () => {
|
||||
authServiceSpy.authenticated = false;
|
||||
authServiceSpy.loginCallback.and.returnValue(Promise.resolve('/fake-route'));
|
||||
|
||||
expect(authGuard.canActivateChild(routeSnapshot, state)).toEqual(true);
|
||||
});
|
||||
await oidcAuthGuard.canActivate();
|
||||
|
||||
expect(authServiceSpy.loginCallback).toHaveBeenCalled();
|
||||
expect(routerSpy.navigateByUrl).toHaveBeenCalledWith('/fake-route', { replaceUrl: true });
|
||||
});
|
||||
|
||||
it('should navigate to default route if loginCallback fails', async () => {
|
||||
authServiceSpy.authenticated = false;
|
||||
authServiceSpy.loginCallback.and.returnValue(Promise.reject(new Error()));
|
||||
|
||||
await oidcAuthGuard.canActivate();
|
||||
|
||||
expect(routerSpy.navigateByUrl).toHaveBeenCalledWith('/', { replaceUrl: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -16,15 +16,17 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanActivate, UrlTree } from '@angular/router';
|
||||
import { CanActivate, Router, UrlTree } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
const ROUTE_DEFAULT = '/';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class OidcAuthGuard implements CanActivate {
|
||||
constructor(private auth: AuthService) {}
|
||||
constructor(private auth: AuthService, private _router: Router) { }
|
||||
|
||||
canActivate(
|
||||
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
||||
@@ -40,13 +42,10 @@ export class OidcAuthGuard implements CanActivate {
|
||||
return true;
|
||||
}
|
||||
|
||||
const loginResult = this.auth.loginCallback({customHashFragment: window.location.search});
|
||||
|
||||
if (loginResult instanceof Promise) {
|
||||
return loginResult.then(() => true).catch(() => false);
|
||||
}
|
||||
|
||||
return false;
|
||||
return this.auth.loginCallback({ customHashFragment: window.location.search })
|
||||
.then(route => this._router.navigateByUrl(route, { replaceUrl: true }))
|
||||
.catch(() => this._router.navigateByUrl(ROUTE_DEFAULT, { replaceUrl: true }));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -16,26 +16,11 @@
|
||||
*/
|
||||
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { from, of } from 'rxjs';
|
||||
import { catchError, first, map } from 'rxjs/operators';
|
||||
import { AuthService } from '../../auth.service';
|
||||
|
||||
const ROUTE_DEFAULT = '/';
|
||||
|
||||
@Component({
|
||||
template: '<div data-automation-id="auth-confirmation"></div>',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class AuthenticationConfirmationComponent {
|
||||
constructor(private auth: AuthService, private _router: Router) {
|
||||
const routeStored$ = from(this.auth.loginCallback()).pipe(
|
||||
map((route) => route || ROUTE_DEFAULT),
|
||||
catchError(() => of(ROUTE_DEFAULT))
|
||||
);
|
||||
|
||||
routeStored$.pipe(first()).subscribe((route) => {
|
||||
this._router.navigateByUrl(route, { replaceUrl: true });
|
||||
});
|
||||
}
|
||||
constructor(){}
|
||||
}
|
||||
|
Reference in New Issue
Block a user