Skip to content

Commit

Permalink
feat(auth): Auth module now support CodeFlow/HybridFlow with PKCE
Browse files Browse the repository at this point in the history
  • Loading branch information
xmlking committed Feb 18, 2019
1 parent 9c113ac commit e098bee
Show file tree
Hide file tree
Showing 25 changed files with 156 additions and 86 deletions.
6 changes: 5 additions & 1 deletion apps/webapp/src/environments/base.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// src/environments/base.ts
const packageJson = require('../../../../package.json');

const base = document.querySelector('base');

export default {
appName: 'Ngx Starter Kit',
secret: 'SECRET',
apiToken: 'SECRET_TOKEN',
baseUrl: (base && base.href) || window.location.origin + '/',
dialogFlow: {
baseUrl: 'https://api.dialogflow.com/v1/query?v=20150910',
apiToken: '37808bf14a19406cbe2a50cfd1332dd3',
Expand All @@ -22,6 +26,6 @@ export default {
flexLayout: packageJson.dependencies['@angular/flex-layout'],
rxjs: packageJson.dependencies.rxjs,
angularCli: packageJson.devDependencies['@angular/cli'],
typescript: packageJson.devDependencies['typescript'],
typescript: packageJson.devDependencies.typescript,
},
};
7 changes: 4 additions & 3 deletions apps/webapp/src/environments/environment.mock.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import sharedEnvironment from './base';
import { IEnvironment } from '@env/ienvironment';

export const environment = {
export const environment: IEnvironment = {
...sharedEnvironment,
production: true,
envName: 'mock',

DOCS_BASE_URL: 'http://localhost:8000',
API_BASE_URL: 'http://localhost:3000/api',
WS_EVENT_BUS_URL: 'ws://localhost:3000/eventbus',

auth: {
clientId: 'ngxapp',
// issuer: 'http://localhost:8080/auth/realms/ngx',
issuer: 'https://keycloak-ngx.1d35.starter-us-east-1.openshiftapps.com/auth/realms/ngx',
clientId: 'ngxapp',
},
};
7 changes: 4 additions & 3 deletions apps/webapp/src/environments/environment.prod.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import sharedEnvironment from './base';
import { IEnvironment } from '@env/ienvironment';

export const environment = {
export const environment: IEnvironment = {
...sharedEnvironment,
production: true,
envName: 'prod',

DOCS_BASE_URL: 'http://localhost:8000',
API_BASE_URL: 'http://localhost:3000/api',
WS_EVENT_BUS_URL: 'ws://localhost:3000/eventbus',

auth: {
clientId: 'ngxapp',
// issuer: 'http://localhost:8080/auth/realms/ngx',
issuer: 'https://keycloak-ngx.1d35.starter-us-east-1.openshiftapps.com/auth/realms/ngx',
clientId: 'ngxapp',
},
};
7 changes: 4 additions & 3 deletions apps/webapp/src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
import sharedEnvironment from './base';
import { IEnvironment } from '@env/ienvironment';

export const environment = {
export const environment: IEnvironment = {
...sharedEnvironment,
production: false,
envName: 'dev',

DOCS_BASE_URL: 'http://localhost:8000',
API_BASE_URL: 'http://localhost:3000/api',
WS_EVENT_BUS_URL: 'ws://localhost:3000/eventbus',

auth: {
clientId: 'ngxapp',
// issuer: 'http://localhost:8080/auth/realms/ngx',
issuer: 'https://keycloak-ngx.1d35.starter-us-east-1.openshiftapps.com/auth/realms/ngx',
clientId: 'ngxapp',
},
};

Expand Down
14 changes: 14 additions & 0 deletions apps/webapp/src/environments/ienvironment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { OidcProviderConfig } from '@ngx-starter-kit/oidc';

export type LogLevel = 'debug' | 'info' | 'warn' | 'error';

export interface IEnvironment {
production: boolean;
envName: string;

// Enables use of ng.profiler.timeChangeDetection(); in browser console
enableDebugTools?: boolean;
logLevel?: LogLevel;
auth?: OidcProviderConfig;
[key: string]: any;
}
6 changes: 3 additions & 3 deletions libs/admin/src/lib/admin.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FormlyModule } from '@ngx-formly/core';
import { FormlyMaterialModule } from '@ngx-formly/material';

import { AdminGuard } from '@ngx-starter-kit/auth';
// import { AuthGuard } from '@ngx-starter-kit/oidc';
import { SharedModule } from '@ngx-starter-kit/shared';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { ToolbarModule } from '@ngx-starter-kit/toolbar';
Expand All @@ -20,8 +21,6 @@ import { NotificationDetailComponent } from './components/notification-detail/no
import { NotificationEditComponent } from './components/notification-edit/notification-edit.component';
import { AdminLayoutComponent } from './containers/admin-layout/admin-layout.component';



import {
MatButtonModule,
MatButtonToggleModule,
Expand Down Expand Up @@ -78,8 +77,9 @@ const matModules = [
{
path: '',
component: AdminLayoutComponent,
// canActivate: [AuthGuard],
canActivate: [AdminGuard],
data: { title: 'Admin', depth: 1 },
data: { title: 'Admin', depth: 1, roles: ['ROLE_ADMIN'] },
children: [
{ path: '', component: OverviewComponent, data: { title: 'Overview', depth: 2 } },
{
Expand Down
2 changes: 1 addition & 1 deletion libs/auth/src/lib/admin.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ export class AdminGuard implements CanActivate {

isAdmin(): boolean {
// const userRoles = (<any>this.oauthService.getIdentityClaims()).groups.filter(role => role.startsWith('NGX_'));
return (<any>this.oauthService.getIdentityClaims()).preferred_username === 'ngxadmin';
return (this.oauthService.getIdentityClaims() as any).preferred_username === 'ngxadmin';
}
}
6 changes: 5 additions & 1 deletion libs/auth/src/lib/auth.actions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export enum AuthMode {
ImplicitFLow = 'ImplicitFLow',
PasswordFlow = 'ROPCFlow',
AuthorizationCodeFLow = 'AuthorizationCodeFLow',
CodeFLow = 'CodeFLow',
HybridFlow = 'HybridFlow',
}

// Actions
Expand All @@ -12,6 +13,9 @@ export class Login {
export class Logout {
static readonly type = '[Auth] Logout';
}
export class Signup {
static readonly type = '[Auth] Signup';
}
export class LoadProfile {
static readonly type = '[Auth] Load Profile';
constructor(public payload: any) {}
Expand Down
6 changes: 1 addition & 5 deletions libs/auth/src/lib/auth.handler.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { Actions, ofActionErrored, ofActionSuccessful } from '@ngxs/store';
import { Injectable } from '@angular/core';
import { Login, LoginSuccess } from './auth.actions';
import { GoogleAnalyticsService } from '@ngx-starter-kit/core/src/lib/services/google-analytics.service';

@Injectable({
providedIn: 'root',
})
export class AuthHandler {
constructor(private actions$: Actions, private analytics: GoogleAnalyticsService) {
constructor(private actions$: Actions) {
this.actions$.pipe(ofActionSuccessful(Login)).subscribe(action => console.log('Login........Action Successful'));
this.actions$.pipe(ofActionErrored(Login)).subscribe(action => console.log('Login........Action Errored'));
this.actions$.pipe(ofActionSuccessful(LoginSuccess)).subscribe((action: LoginSuccess) => {
this.analytics.setUsername(action.payload.preferred_username);
});
}
}
11 changes: 3 additions & 8 deletions libs/auth/src/lib/auth.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { Store } from '@ngxs/store';
import { NgxsModule, Store } from '@ngxs/store';
import { JwksValidationHandler, OAuthModule, OAuthService, ValidationHandler } from '@xmlking/angular-oauth2-oidc-all';

import { environment } from '@env/environment';
Expand Down Expand Up @@ -44,6 +44,7 @@ const matModules = [
@NgModule({
imports: [
CommonModule,
NgxsModule.forFeature([AuthState]),
RouterModule,
[...matModules],
FlexLayoutModule,
Expand All @@ -58,13 +59,7 @@ const matModules = [
],
declarations: [LoginComponent],
entryComponents: [LoginComponent],
providers: [
AuthState,
ROPCService,
AuthService,
AuthGuard,
{ provide: ValidationHandler, useClass: JwksValidationHandler },
],
providers: [ROPCService, AuthService, AuthGuard, { provide: ValidationHandler, useClass: JwksValidationHandler }],
})
export class AuthModule {
static forRoot(): ModuleWithProviders {
Expand Down
32 changes: 16 additions & 16 deletions libs/auth/src/lib/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { OAuthEvent } from '@xmlking/angular-oauth2-oidc-all/events';
@Injectable()
export class AuthService {
static loginDefaultConf = { width: '380px', disableClose: true, panelClass: 'mylogin-no-padding-dialog' };
private _refresher: Subscription;
private _monitorer: Subscription;
private refresher: Subscription;
private monitorer: Subscription;
// @Select('auth.authMode') authMode$: Observable<AuthMode>;
authMode: AuthMode;

Expand All @@ -37,7 +37,7 @@ export class AuthService {
}

private monitorSessionActivities() {
this._monitorer = this.oauthService.events.subscribe(e => {
this.monitorer = this.oauthService.events.subscribe(e => {
switch (e.type) {
case 'logout':
case 'session_terminated':
Expand Down Expand Up @@ -77,28 +77,31 @@ export class AuthService {
// For Password Flow
return this.ropcService.logOut();
} else {
// For ImplicitFlow
// For ImplicitFlow or CodeFLow or HybridFlow
this.oauthService.logOut();
}
}

stopAutoRefreshToken() {
if (this._refresher && !this._refresher.closed) {
this._refresher.unsubscribe();
if (this.refresher && !this.refresher.closed) {
this.refresher.unsubscribe();
}
}

startAutoRefreshToken() {
if (this._refresher && !this._refresher.closed) {
this._refresher.unsubscribe();
if (this.refresher && !this.refresher.closed) {
this.refresher.unsubscribe();
}
if (this._monitorer && !this._monitorer.closed) {
this._monitorer.unsubscribe();
if (this.monitorer && !this.monitorer.closed) {
this.monitorer.unsubscribe();
}

if (this.authMode === AuthMode.PasswordFlow) {
// for Password Flow
this._refresher = this.oauthService.events
if (this.authMode === AuthMode.ImplicitFLow) {
// for Implicit flow
this.oauthService.setupAutomaticSilentRefresh();
} else {
// for PasswordFlow or CodeFLow or HybridFlow
this.refresher = this.oauthService.events
.pipe(
tap(e => {
console.log(`sumo: type: $e.type, `, e);
Expand All @@ -112,9 +115,6 @@ export class AuthService {
}),
)
.subscribe();
} else {
// for Implicit flow
this.oauthService.setupAutomaticSilentRefresh();
}

this.monitorSessionActivities();
Expand Down
30 changes: 19 additions & 11 deletions libs/auth/src/lib/auth.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from './auth.actions';
import { AuthService } from './auth.service';
import { Router } from '@angular/router';
import { authConfigImplicit, authConfigPassword } from './oauth.config';
import { authConfigCodeFlow, authConfigHybridFlow, authConfigImplicit, authConfigPassword } from './oauth.config';
import { OAuthService } from '@xmlking/angular-oauth2-oidc-all';
import { map } from 'rxjs/operators';

Expand Down Expand Up @@ -91,6 +91,12 @@ export class AuthState {
case AuthMode.PasswordFlow:
this.oauthService.configure(authConfigPassword);
break;
case AuthMode.CodeFLow:
this.oauthService.configure(authConfigCodeFlow);
break;
case AuthMode.HybridFlow:
this.oauthService.configure(authConfigHybridFlow);
break;
default:
this.oauthService.configure(authConfigImplicit);
break;
Expand All @@ -107,15 +113,17 @@ export class AuthState {

@Action(Login)
login({ getState, dispatch }: StateContext<AuthStateModel>, { payload }: Login) {
// HINT: done escape form zone https://github.com/angular/material2/issues/13640
return this.zone.run( () => this.authService.login(payload).pipe(
map(profile => {
if (profile === false) {
dispatch(new LoginCanceled());
} else {
dispatch(new LoginSuccess(profile));
}
}),
));
// HINT: don't escape form zone https://github.com/angular/material2/issues/13640
return this.zone.run(() =>
this.authService.login(payload).pipe(
map(profile => {
if (profile === false) {
dispatch(new LoginCanceled());
} else {
dispatch(new LoginSuccess(profile));
}
}),
),
);
}
}
9 changes: 5 additions & 4 deletions libs/auth/src/lib/components/login/login.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import { ChangeAuthMode, AuthMode } from '../../auth.actions';
styleUrls: ['./login.component.scss'],
})
export class LoginComponent {
public infoMsg: String;
public errorMsg: String;
public infoMsg: string;
public errorMsg: string;
inputType = 'password';
visible = false;
loginForm: FormGroup;
Expand Down Expand Up @@ -53,8 +53,9 @@ export class LoginComponent {
}

initSSO() {
this.store.dispatch(new ChangeAuthMode(AuthMode.ImplicitFLow)).subscribe(() => {
this.oauthService.initImplicitFlow();
this.store.dispatch(new ChangeAuthMode(AuthMode.CodeFLow)).subscribe(() => {
// this.oauthService.initImplicitFlow();
this.oauthService.initAuthorizationCodeFlow();
console.log('initSSO');
});
}
Expand Down
Loading

0 comments on commit e098bee

Please sign in to comment.