Skip to content

Commit

Permalink
AAE-25816 Provide a separate storage instance for the AuthModule to a…
Browse files Browse the repository at this point in the history
…llow setting a custom storage prefix for authentication data stored in local storage
  • Loading branch information
alep85 committed Sep 17, 2024
1 parent 5981822 commit 5b0c0af
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 10 deletions.
1 change: 1 addition & 0 deletions lib/core/src/lib/auth/oidc/auth-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
17 changes: 13 additions & 4 deletions lib/core/src/lib/auth/oidc/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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
};
}
}
1 change: 1 addition & 0 deletions lib/core/src/lib/auth/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
44 changes: 44 additions & 0 deletions lib/core/src/lib/auth/services/custom-auth-storage.service.spec.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
33 changes: 33 additions & 0 deletions lib/core/src/lib/auth/services/custom-auth-storage.service.ts
Original file line number Diff line number Diff line change
@@ -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;
});
}
}
6 changes: 5 additions & 1 deletion lib/core/src/lib/auth/services/jwt-helper.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@
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', () => {

let jwtHelperService: JwtHelperService;

beforeEach(() => {
TestBed.configureTestingModule({
providers: [JwtHelperService]
providers: [
JwtHelperService,
{ provide: STORAGE_SERVICE, useValue: {} }
]
});
jwtHelperService = TestBed.inject(JwtHelperService);
});
Expand Down
7 changes: 3 additions & 4 deletions lib/core/src/lib/auth/services/jwt-helper.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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.
Expand Down
1 change: 1 addition & 0 deletions lib/core/src/lib/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
29 changes: 29 additions & 0 deletions lib/core/src/lib/common/interface/storage-service.interface.ts
Original file line number Diff line number Diff line change
@@ -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;
}
3 changes: 2 additions & 1 deletion lib/core/src/lib/common/services/storage.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '';
Expand Down
2 changes: 2 additions & 0 deletions lib/core/src/lib/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -138,6 +139,7 @@ export class CoreModule {
TranslateService,
{ provide: TranslateLoader, useClass: TranslateLoaderService },
MomentDateAdapter,
{ provide: STORAGE_SERVICE, useExisting: StorageService },
StoragePrefixFactory,
{
provide: APP_INITIALIZER,
Expand Down

0 comments on commit 5b0c0af

Please sign in to comment.