Commit 8fde9eec authored by François Agneray's avatar François Agneray

Update auth module

parent 39099947
Pipeline #3502 passed with stages
in 8 minutes and 41 seconds
......@@ -15,6 +15,9 @@ export const LOGIN = '[Auth] Login';
export const LOGIN_COMPLETE = '[Auth] Login Complete';
export const LOGOUT = '[Auth] Logout';
export const OPEN_EDIT_PROFILE = '[Auth] Edit Profile';
export const GET_USER_ROLES = '[Auth] Get User Roles';
export const PARSE_JWT = '[Auth] Parse JWT';
export const LOAD_USER_ROLES = '[Auth] Load User Roles';
export class CheckAuthAction implements Action {
readonly type = CHECK_AUTH;
......@@ -63,10 +66,24 @@ export class OpenEditProfileAction implements Action {
constructor(public payload: {} = null) { }
}
export class ParseJwtAction implements Action {
readonly type = PARSE_JWT;
constructor(public payload: string) { }
}
export class LoadUserRolesAction implements Action {
readonly type = LOAD_USER_ROLES;
constructor(public payload: string[]) { }
}
export type Actions
= CheckAuthAction
| CheckAuthCompleteAction
| LoginAction
| LoginCompleteAction
| LogoutAction
| OpenEditProfileAction;
| OpenEditProfileAction
| ParseJwtAction
| LoadUserRolesAction;
......@@ -13,6 +13,7 @@ import { Router } from '@angular/router';
import { of } from 'rxjs';
import { switchMap, map, tap } from 'rxjs/operators';
import { Effect, Actions, ofType } from '@ngrx/effects';
import jwt_decode from 'jwt-decode';
import * as authActions from './auth.action';
import { AuthService } from './auth.service';
......@@ -39,7 +40,7 @@ export class AuthEffects {
tap((action: authActions.LoginAction) => {
const redirectUrl = action.payload;
if (redirectUrl !== null) {
sessionStorage.setItem(environment.ssoClientId + '_redirectUrl', this.router.url);
sessionStorage.setItem(environment.ssoClientId + '_redirectUrl', redirectUrl);
}
return this.authService.doLogin()
})
......@@ -65,9 +66,10 @@ export class AuthEffects {
if (isAuthenticated) {
return this.authService.userData.pipe(
map((profile) =>
new authActions.LoginCompleteAction(profile)
)
switchMap((profile) => [
new authActions.LoginCompleteAction(profile),
new authActions.ParseJwtAction(this.authService.token)
])
);
} else {
return of({ type: '[No Action] ' + authActions.CHECK_AUTH_COMPLETE });
......@@ -87,6 +89,19 @@ export class AuthEffects {
})
);
@Effect()
parseJWTAction$ = this.actions$.pipe(
ofType(authActions.PARSE_JWT),
switchMap((action: authActions.ParseJwtAction) => {
const jwt = jwt_decode(action.payload) as any;
if (environment.ssoName === 'auth0') {
return of({ type: '[No Action] ' + authActions.PARSE_JWT });
} else {
return of(new authActions.LoadUserRolesAction(jwt.realm_access.roles));
}
})
);
@Effect({ dispatch: false })
logoutAction$ = this.actions$.pipe(
ofType(authActions.LOGOUT),
......
......@@ -17,11 +17,13 @@ import * as actions from './auth.action';
export interface State {
isAuthenticated: boolean;
userProfile: any;
userRoles: string[];
}
export const initialState: State = {
isAuthenticated: false,
userProfile: null
userProfile: null,
userRoles: []
};
/**
......@@ -43,6 +45,14 @@ export function reducer(state: State = initialState, action: actions.Actions): S
userProfile
};
case actions.LOAD_USER_ROLES:
const userRoles = action.payload;
return {
...state,
userRoles
};
case actions.LOGOUT:
return {
...state,
......@@ -57,3 +67,4 @@ export function reducer(state: State = initialState, action: actions.Actions): S
export const isAuthenticated = (state: State) => state.isAuthenticated;
export const getUserProfile = (state: State) => state.userProfile;
export const getUserRoles = (state: State) => state.userRoles;
......@@ -11,14 +11,19 @@ import { createSelector, createFeatureSelector } from '@ngrx/store';
import * as auth from './auth.reducer';
export const getAuthtate = createFeatureSelector<auth.State>('auth');
export const getAuthState = createFeatureSelector<auth.State>('auth');
export const isAuthenticated = createSelector(
getAuthtate,
getAuthState,
auth.isAuthenticated
);
export const getUserProfile = createSelector(
getAuthtate,
getAuthState,
auth.getUserProfile
);
export const getUserRoles = createSelector(
getAuthState,
auth.getUserRoles
);
......@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { OidcSecurityService } from 'angular-auth-oidc-client';
import { environment } from 'src/environments/environment';
@Injectable({ providedIn: 'root' })
export class AuthService {
......@@ -12,7 +13,11 @@ export class AuthService {
}
get token() {
return this.oidcSecurityService.getIdToken();
if (environment.ssoName === 'auth0') {
return this.oidcSecurityService.getIdToken();
} else {
return this.oidcSecurityService.getToken();
}
}
get userData() {
......
......@@ -49,12 +49,12 @@
<span class="dropdown-item font-italic">{{ userProfile.email }}</span>
</li>
<li class="divider dropdown-divider"></li>
<li role="menuitem">
<li *ngIf="ssoName != 'auth0'" role="menuitem">
<button class="dropdown-item pointer" (click)="openEditProfile.emit()">
<span class="fas fa-id-card"></span> Edit profile
</button>
</li>
<li class="divider dropdown-divider"></li>
<li *ngIf="ssoName != 'auth0'" class="divider dropdown-divider"></li>
<li role="menuitem">
<button class="dropdown-item text-danger pointer" (click)="logout.emit()">
<span class="fas fa-sign-out-alt fa-fw"></span> Sign Out
......@@ -96,12 +96,12 @@
</a>
</li>
<li *ngIf="getConfig('authentication', 'allowed') && isAuthenticated" class="divider dropdown-divider"></li>
<li *ngIf="getConfig('authentication', 'allowed') && isAuthenticated" role="menuitem">
<li *ngIf="getConfig('authentication', 'allowed') && isAuthenticated && ssoName != 'auth0'" role="menuitem">
<button class="dropdown-item pointer" (click)="openEditProfile.emit()">
<span class="fas fa-id-card"></span> Edit profile
</button>
</li>
<li *ngIf="getConfig('authentication', 'allowed')" class="divider dropdown-divider"></li>
<li *ngIf="getConfig('authentication', 'allowed') && ssoName != 'auth0'" class="divider dropdown-divider"></li>
<li role="menuitem">
<button *ngIf="getConfig('authentication', 'allowed') && !isAuthenticated"
class="dropdown-item text-success"
......
......@@ -31,6 +31,7 @@ export class NavComponent {
@Output() openEditProfile: EventEmitter<any> = new EventEmitter();
baseHref: string = environment.baseHref;
ssoName: string = environment.ssoName;
/**
* Checks if given key for the given configuration propriety is allowed.
......
......@@ -14,6 +14,7 @@ export const environment = {
spectraUrl: 'https://cesam.lam.fr/anis-tools/spectra_to_csv/?file=/dataproject/SPECTRA/',
instanceName: 'default',
baseHref: '/',
ssoName: 'keycloak',
ssoAuthUrl: 'https://anis-dev.lam.fr/auth/realms/anis',
ssoClientId: 'anis-client'
};
......@@ -18,6 +18,7 @@ export const environment = {
spectraUrl: 'https://cesam.lam.fr/anis-tools/spectra_to_csv/?file=/dataproject/SPECTRA/',
instanceName: 'default',
baseHref: '/',
ssoName: 'keycloak',
ssoAuthUrl: 'http://localhost:8180/auth/realms/anis',
ssoClientId: 'anis-client'
};
......@@ -5962,6 +5962,11 @@ jszip@^3.1.3:
readable-stream "~2.3.6"
set-immediate-shim "~1.0.1"
jwt-decode@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59"
integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==
karma-chrome-launcher@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz#805a586799a4d05f4e54f72a204979f3f3066738"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment