bug fixes for auth service

This commit is contained in:
Denys Vuika
2023-11-17 15:16:36 +00:00
parent d14c116747
commit 177612c7d9
4 changed files with 151 additions and 138 deletions
@@ -81,6 +81,13 @@ export class AppConfigService {
return this.status === Status.LOADED; return this.status === Status.LOADED;
} }
/**
* Returns current authentication type as configured via `authType` property.
*/
get authType(): 'OAUTH' | 'BASIC' {
return this.get('authType');
}
constructor(protected http: HttpClient, protected extensionService: ExtensionService) { constructor(protected http: HttpClient, protected extensionService: ExtensionService) {
this.onLoadSubject = new ReplaySubject(); this.onLoadSubject = new ReplaySubject();
this.onLoad = this.onLoadSubject.asObservable(); this.onLoad = this.onLoadSubject.asObservable();
@@ -40,11 +40,6 @@ export class AuthConfigService {
@Inject(AUTH_MODULE_CONFIG) private readonly authModuleConfig: AuthModuleConfig @Inject(AUTH_MODULE_CONFIG) private readonly authModuleConfig: AuthModuleConfig
) {} ) {}
private _authConfig!: AuthConfig;
get authConfig(): AuthConfig {
return this._authConfig;
}
loadConfig(): Promise<AuthConfig> { loadConfig(): Promise<AuthConfig> {
return this.appConfigService.onLoad.pipe(take(1)).toPromise().then(this.loadAppConfig.bind(this)); return this.appConfigService.onLoad.pipe(take(1)).toPromise().then(this.loadAppConfig.bind(this));
} }
+5 -5
View File
@@ -27,6 +27,7 @@ import { AuthRoutingModule } from './auth-routing.module';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { RedirectAuthService } from './redirect-auth.service'; import { RedirectAuthService } from './redirect-auth.service';
import { AuthenticationConfirmationComponent } from './view/authentication-confirmation/authentication-confirmation.component'; import { AuthenticationConfirmationComponent } from './view/authentication-confirmation/authentication-confirmation.component';
import { AppConfigService } from '../../app-config/app-config.service';
/** /**
* Create a Login Factory function * Create a Login Factory function
@@ -36,8 +37,8 @@ import { AuthenticationConfirmationComponent } from './view/authentication-confi
* @param config auth configuration * @param config auth configuration
* @returns a factory function * @returns a factory function
*/ */
export function loginFactory(oAuthService: OAuthService, storage: OAuthStorage, config: AuthConfig) { export function loginFactory(oAuthService: OAuthService, storage: OAuthStorage, appConfig: AppConfigService, config: AuthConfig) {
const service = new RedirectAuthService(oAuthService, storage, config); const service = new RedirectAuthService(oAuthService, storage, appConfig, config);
return () => service.init(); return () => service.init();
} }
@@ -49,19 +50,18 @@ export function loginFactory(oAuthService: OAuthService, storage: OAuthStorage,
// { provide: AuthGuard, useClass: OidcAuthGuard }, // { provide: AuthGuard, useClass: OidcAuthGuard },
// { provide: AuthGuardEcm, useClass: OidcAuthGuard }, // { provide: AuthGuardEcm, useClass: OidcAuthGuard },
// { provide: AuthGuardBpm, useClass: OidcAuthGuard }, // { provide: AuthGuardBpm, useClass: OidcAuthGuard },
{ provide: AuthenticationService}, AuthenticationService,
{ provide: AlfrescoApiService, useClass: AlfrescoApiNoAuthService }, { provide: AlfrescoApiService, useClass: AlfrescoApiNoAuthService },
{ {
provide: AUTH_CONFIG, provide: AUTH_CONFIG,
useFactory: authConfigFactory, useFactory: authConfigFactory,
deps: [AuthConfigService] deps: [AuthConfigService]
}, },
RedirectAuthService,
{ provide: AuthService, useExisting: RedirectAuthService }, { provide: AuthService, useExisting: RedirectAuthService },
{ {
provide: APP_INITIALIZER, provide: APP_INITIALIZER,
useFactory: loginFactory, useFactory: loginFactory,
deps: [OAuthService, OAuthStorage, AUTH_CONFIG], deps: [OAuthService, OAuthStorage, AUTH_CONFIG, AppConfigService],
multi: true multi: true
} }
] ]
@@ -21,12 +21,12 @@ import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
import { from, Observable } from 'rxjs'; import { from, Observable } from 'rxjs';
import { distinctUntilChanged, filter, map, shareReplay } from 'rxjs/operators'; import { distinctUntilChanged, filter, map, shareReplay } from 'rxjs/operators';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { AppConfigService } from '../../app-config/app-config.service';
const isPromise = <T>(value: T | Promise<T>): value is Promise<T> => value && typeof (value as Promise<T>).then === 'function'; const isPromise = <T>(value: T | Promise<T>): value is Promise<T> => value && typeof (value as Promise<T>).then === 'function';
@Injectable() @Injectable({ providedIn: 'root' })
export class RedirectAuthService extends AuthService { export class RedirectAuthService extends AuthService {
onLogin: Observable<any>; onLogin: Observable<any>;
private _loadDiscoveryDocumentPromise = Promise.resolve(false); private _loadDiscoveryDocumentPromise = Promise.resolve(false);
@@ -50,7 +50,8 @@ export class RedirectAuthService extends AuthService {
constructor( constructor(
private oauthService: OAuthService, private oauthService: OAuthService,
private _oauthStorage: OAuthStorage, private oauthStorage: OAuthStorage,
private appConfig: AppConfigService,
@Inject(AUTH_CONFIG) authConfig: AuthConfig @Inject(AUTH_CONFIG) authConfig: AuthConfig
) { ) {
super(); super();
@@ -75,7 +76,7 @@ export class RedirectAuthService extends AuthService {
); );
} }
init() { async init() {
if (isPromise(this.authConfig)) { if (isPromise(this.authConfig)) {
return this.authConfig.then((config) => this.configureAuth(config)); return this.authConfig.then((config) => this.configureAuth(config));
} }
@@ -88,6 +89,10 @@ export class RedirectAuthService extends AuthService {
} }
ensureDiscoveryDocument(): Promise<boolean> { ensureDiscoveryDocument(): Promise<boolean> {
if (this.appConfig.authType === 'BASIC') {
return Promise.resolve(true);
}
this._loadDiscoveryDocumentPromise = this._loadDiscoveryDocumentPromise this._loadDiscoveryDocumentPromise = this._loadDiscoveryDocumentPromise
.catch(() => false) .catch(() => false)
.then((loaded) => { .then((loaded) => {
@@ -99,14 +104,13 @@ export class RedirectAuthService extends AuthService {
return this._loadDiscoveryDocumentPromise; return this._loadDiscoveryDocumentPromise;
} }
login(currentUrl?: string): void { login(currentUrl?: string): void {
let stateKey: string | undefined; let stateKey: string | undefined;
if (currentUrl) { if (currentUrl) {
const randomValue = window.crypto.getRandomValues(new Uint32Array(1))[0]; const randomValue = window.crypto.getRandomValues(new Uint32Array(1))[0];
stateKey = `auth_state_${randomValue}${Date.now()}`; stateKey = `auth_state_${randomValue}${Date.now()}`;
this._oauthStorage.setItem(stateKey, JSON.stringify(currentUrl || {})); this.oauthStorage.setItem(stateKey, JSON.stringify(currentUrl || {}));
} }
// initLoginFlow will initialize the login flow in either code or implicit depending on the configuration // initLoginFlow will initialize the login flow in either code or implicit depending on the configuration
@@ -121,7 +125,13 @@ export class RedirectAuthService extends AuthService {
const props = new Map<string, string>(); const props = new Map<string, string>();
props.set('id_token', response.id_token); props.set('id_token', response.id_token);
// for backward compatibility we need to set the response in our storage // for backward compatibility we need to set the response in our storage
this.oauthService['storeAccessTokenResponse'](response.access_token, response.refresh_token, response.expires_in, response.scope, props); this.oauthService['storeAccessTokenResponse'](
response.access_token,
response.refresh_token,
response.expires_in,
response.scope,
props
);
return response; return response;
}) })
); );
@@ -138,10 +148,10 @@ export class RedirectAuthService extends AuthService {
const stateKey = this.oauthService.state; const stateKey = this.oauthService.state;
if (stateKey) { if (stateKey) {
const stateStringified = this._oauthStorage.getItem(stateKey); const stateStringified = this.oauthStorage.getItem(stateKey);
if (stateStringified) { if (stateStringified) {
// cleanup state from storage // cleanup state from storage
this._oauthStorage.removeItem(stateKey); this.oauthStorage.removeItem(stateKey);
return JSON.parse(stateStringified); return JSON.parse(stateStringified);
} }
} }
@@ -149,7 +159,7 @@ export class RedirectAuthService extends AuthService {
return DEFAULT_REDIRECT; return DEFAULT_REDIRECT;
} }
private configureAuth(config: AuthConfig) { private async configureAuth(config: AuthConfig) {
this.oauthService.configure(config); this.oauthService.configure(config);
this.oauthService.tokenValidationHandler = new JwksValidationHandler(); this.oauthService.tokenValidationHandler = new JwksValidationHandler();
@@ -159,11 +169,12 @@ export class RedirectAuthService extends AuthService {
}); });
} }
return this.ensureDiscoveryDocument().then(() => try {
void this.oauthService.setupAutomaticSilentRefresh() await this.ensureDiscoveryDocument();
).catch(() => { return void this.oauthService.setupAutomaticSilentRefresh();
// catch error to prevent the app from crashing when trying to access unprotected routes } catch {
}); // do nothing
}
} }
updateIDPConfiguration(config: AuthConfig) { updateIDPConfiguration(config: AuthConfig) {