AAE-25816 Provide a separate storage instance for the AuthModule to allow setting a custom storage prefix for authentication data stored in local storage

This commit is contained in:
alep85 2024-09-16 19:05:51 +02:00
parent 59818226aa
commit 5b0c0affd5
No known key found for this signature in database
GPG Key ID: AB4BE8E091FD24C8
11 changed files with 134 additions and 10 deletions

View File

@ -20,6 +20,7 @@ import { InjectionToken } from '@angular/core';
export interface AuthModuleConfig {
readonly useHash: boolean;
preventClearHashAfterLogin?: boolean;
overrideAuthStoragePrefix?: boolean;
}
export const AUTH_MODULE_CONFIG = new InjectionToken<AuthModuleConfig>('AUTH_MODULE_CONFIG');

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
import { APP_INITIALIZER, EnvironmentProviders, ModuleWithProviders, NgModule, Provider } from '@angular/core';
import { AUTH_CONFIG, OAuthModule, OAuthStorage } from 'angular-oauth2-oidc';
import { AuthenticationService } from '../services/authentication.service';
import { StorageService } from '../../common/services/storage.service';
@ -25,6 +25,8 @@ import { AuthRoutingModule } from './auth-routing.module';
import { AuthService } from './auth.service';
import { RedirectAuthService } from './redirect-auth.service';
import { AuthenticationConfirmationComponent } from './view/authentication-confirmation/authentication-confirmation.component';
import { CustomAuthStorageService } from '../services/custom-auth-storage.service';
import { STORAGE_SERVICE } from '../../common/interface/storage-service.interface';
/**
* Create a Login Factory function
@ -41,7 +43,7 @@ export function loginFactory(redirectService: RedirectAuthService): () => Promis
imports: [AuthRoutingModule, OAuthModule.forRoot()],
providers: [
{ provide: OAuthStorage, useExisting: StorageService },
{ provide: AuthenticationService},
{ provide: AuthenticationService },
{
provide: AUTH_CONFIG,
useFactory: authConfigFactory,
@ -58,11 +60,18 @@ export function loginFactory(redirectService: RedirectAuthService): () => Promis
]
})
export class AuthModule {
static forRoot(config: AuthModuleConfig = { useHash: false }): ModuleWithProviders<AuthModule> {
static forRoot(config: AuthModuleConfig = { useHash: false, overrideAuthStoragePrefix: false }): ModuleWithProviders<AuthModule> {
config.preventClearHashAfterLogin = config.preventClearHashAfterLogin ?? true;
const providers: (Provider | EnvironmentProviders)[] = [
{ provide: AUTH_MODULE_CONFIG, useValue: config }
];
if(config.overrideAuthStoragePrefix){
providers.push({ provide: OAuthStorage, useClass: CustomAuthStorageService });
providers.push({ provide: STORAGE_SERVICE, useExisting: OAuthStorage });
}
return {
ngModule: AuthModule,
providers: [{ provide: AUTH_MODULE_CONFIG, useValue: config }]
providers
};
}
}

View File

@ -30,6 +30,7 @@ export * from './services/identity-group.service';
export * from './services/jwt-helper.service';
export * from './services/oauth2.service';
export * from './services/user-access.service';
export * from './services/custom-auth-storage.service';
export * from './basic-auth/basic-alfresco-auth.service';
export * from './basic-auth/process-auth';

View File

@ -0,0 +1,44 @@
/*!
* @license
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { CUSTOM_AUTH_STORAGE_PREFIX, CustomAuthStorageService } from './custom-auth-storage.service';
describe('CustomAuthStorageService', () => {
let service: CustomAuthStorageService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
CustomAuthStorageService,
{ provide: CUSTOM_AUTH_STORAGE_PREFIX, useValue: of('custom-prefix') }
]
});
service = TestBed.inject(CustomAuthStorageService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should set the prefix from the observable', () => {
const expectedPrefix = 'custom-prefix_';
expect(service.prefix).toBe(expectedPrefix);
});
});

View File

@ -0,0 +1,33 @@
/*!
* @license
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Inject, Injectable, InjectionToken } from '@angular/core';
import { StorageService } from '../../common/services/storage.service';
import { Observable } from 'rxjs';
export const CUSTOM_AUTH_STORAGE_PREFIX = new InjectionToken<any>('CUSTOM_AUTH_STORAGE_PREFIX');
@Injectable()
export class CustomAuthStorageService extends StorageService {
constructor(@Inject(CUSTOM_AUTH_STORAGE_PREFIX) customAuthStoragePrefix$: Observable<string>) {
super();
customAuthStoragePrefix$.subscribe(prefix => {
this.prefix = prefix;
});
}
}

View File

@ -18,6 +18,7 @@
import { JwtHelperService } from './jwt-helper.service';
import { mockToken } from '../mock/jwt-helper.service.spec';
import { TestBed } from '@angular/core/testing';
import { STORAGE_SERVICE } from '../../common';
describe('JwtHelperService', () => {
@ -25,7 +26,10 @@ describe('JwtHelperService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [JwtHelperService]
providers: [
JwtHelperService,
{ provide: STORAGE_SERVICE, useValue: {} }
]
});
jwtHelperService = TestBed.inject(JwtHelperService);
});

View File

@ -15,8 +15,8 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { StorageService } from '../../common/services/storage.service';
import { Inject, Injectable } from '@angular/core';
import { STORAGE_SERVICE, StorageServiceInterface } from '../../common/interface/storage-service.interface';
@Injectable({
providedIn: 'root'
@ -34,8 +34,7 @@ export class JwtHelperService {
static USER_PREFERRED_USERNAME = 'preferred_username';
static HXP_AUTHORIZATION = 'hxp_authorization';
constructor(private storageService: StorageService) {
}
constructor(@Inject(STORAGE_SERVICE) private storageService: StorageServiceInterface) {}
/**
* Decodes a JSON web token into a JS object.

View File

@ -32,6 +32,7 @@ export * from './models/log-levels.model';
export * from './models/user-info-mode.enum';
export * from './interface/search-component.interface';
export * from './interface/storage-service.interface';
export * from './mock/app-config.service.mock';

View File

@ -0,0 +1,29 @@
/*!
* @license
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { InjectionToken } from '@angular/core';
export const STORAGE_SERVICE = new InjectionToken<StorageServiceInterface>('STORAGE_SERVICE');
export interface StorageServiceInterface {
prefix: string;
getItem(key: string): string | null;
setItem(key: string, data: string): void;
clear(): void;
removeItem(key: string): void;
hasItem(key: string): boolean;
}

View File

@ -16,11 +16,12 @@
*/
import { Injectable } from '@angular/core';
import { StorageServiceInterface } from '../interface/storage-service.interface';
@Injectable({
providedIn: 'root'
})
export class StorageService {
export class StorageService implements StorageServiceInterface {
private memoryStore: { [key: string]: any } = {};
private readonly useLocalStorage: boolean = false;
private _prefix: string = '';

View File

@ -50,6 +50,7 @@ import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
import { loadAppConfig } from './app-config/app-config.loader';
import { AppConfigService } from './app-config/app-config.service';
import { StorageService } from './common/services/storage.service';
import { STORAGE_SERVICE } from './common/interface/storage-service.interface';
import { MomentDateAdapter } from './common/utils/moment-date-adapter';
import { AppConfigPipe, StoragePrefixFactory } from './app-config';
import { IconComponent } from './icon';
@ -138,6 +139,7 @@ export class CoreModule {
TranslateService,
{ provide: TranslateLoader, useClass: TranslateLoaderService },
MomentDateAdapter,
{ provide: STORAGE_SERVICE, useExisting: StorageService },
StoragePrefixFactory,
{
provide: APP_INITIALIZER,