Reputation: 1035
The application I'm working implements Azure Active Directory authorization through an adal.js port for Angular 2+, which works perfectly.
We have an AuthenticationGuard
that handles the calls to/from our own AdalService
. The AdalService
has a function ensureAuthenticatedAsync
which checks whether the user is logged in and if not, redirects him to the AD login page.
We now have the new requirement to be able to alternatively sign in with a custom generated token without when no AD account is available. After some modifications, my code looks like this:
authentication.guard.ts
public canActivate(route: ActivatedRouteSnapshot, state RouterStateSnapshot) : boolean {
...
let params = route.queryParams;
let token = (params !== null && params['token'] !== undefined) ? params['token'] : null;
this.adalService.ensureAuthenticatedAsync(token);
...
return true;
}
adal.service.ts
private context: adal.AuthenticationContext;
public ensureAuthenticatedAsync(token: string | null = null) {
console.log('ensureAuthenticatedAsync', token);
this.isAuthenticated.subscribe(isAuthenticated => {
if (!isAuthenticated) {
console.log('not authenticated);
if (token === null) {
// forward to AAD login page -> this works perfectly
this.context.login();
} else {
...
console.log('accessToken before', this.accessToken);
this.customToken = token;
console.log('accessToken after', this.accessToken);
...
}
}
});
}
public get accessToken(): string {
console.log('customToken in get accessToken', this.customToken);
return (this.customToken === null) ? this.context.getCachedToken(this.adalClientId) : this.customToken;
}
public get isAuthenticated(): Observable<boolean> {
console.log('accessToken in get isAuthenticated', this.accessToken);
let isAuthenticated: boolean = (this.accessToken !== null);
return Observable.of(isAuthenticated);
}
app.component.ts
public ngOnInit(): void {
this.adalService.isAuthenticated.subscribe(isAuthenticated => {
if (isAuthenticated) {
// do some stuff here
}
});
}
app.routes.ts
export const ROUTES: Routes = [
{ path: 'Dashboard', component: DashboardComponent, canActivate: [AuthenticationGuard] },
{ path: 'Access-Denied', component: AccessDeniedComponent }
];
This is what's logged in the console:
authentication guard
customToken in get accessToken null
accessToken in get isAuthenticated null
customToken in get accessToken null
ensureAuthenticatedAsync 12345
not authenticated
customToken in get accessToken null
accessToken before null
customToken in get accessToken 12345
accessToken after 12345
customToken in get accessToken 12345
Accessing the page regularly (http://localhost:3000/Dashboard) correctly triggers a redirect to the AD login page, which then returns to my application after login. There, the cacheed AD token is changed and isAuthenticated is triggered wherever it is subscribed to (in my case in app.component.ts
).
However, accessing the page using a token (http://localhost:3000/Dashboard/?token=12345) does not work. Even though customToken
is modified with the value in the param, changes don't seem to be propagated and isAuthenticated stays false
in the subscription(s).
Did I miss something?
Upvotes: 2
Views: 1414
Reputation: 7221
I think the problem is about the guard localization.
Your guard is on /Dashboard route. So if you load only http://localhost:3000/?token=12345 your AuthenticationGuard is not called, thus ensureAuthenticatedAsync is not called either. So you have no redirection and not update of customToken in adal.service.ts.
If you want to use the computed result of you guard in appComponent you must use the guard on the route "leading" to appComponent
EDIT : The problem is that you misunderstand the reactive behavior. the way isAuthenticated is implemented it will emit a boolean one time and then complete. So your subscription in app.component will trigger only once.
What you are looking for is behavior subject, where you could "push" new data when needed or when customToken change.
Upvotes: 2
Reputation: 396
Try:
in your adal.service.ts :
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
...
public get isAuthenticated(): Observable<boolean> {
let isAuthenticated: boolean = (this.accessToken !== null);
return of(isAuthenticated);
}
Upvotes: 1