feat(core/auth): add TimeSyncDateTimeProvider for angular-oauth2-oidc clock drift correction

This commit is contained in:
copilot-swe-agent[bot]
2026-07-02 09:48:35 +00:00
committed by GitHub
parent c9d1517f45
commit 4c2de33cf1
4 changed files with 117 additions and 1 deletions
+3 -1
View File
@@ -16,7 +16,7 @@
*/
import { inject, ModuleWithProviders, NgModule, InjectionToken, provideAppInitializer, EnvironmentProviders, Provider } from '@angular/core';
import { AUTH_CONFIG, OAuthStorage, provideOAuthClient } from 'angular-oauth2-oidc';
import { AUTH_CONFIG, DateTimeProvider, OAuthStorage, provideOAuthClient } from 'angular-oauth2-oidc';
import { AuthenticationService } from '../services/authentication.service';
import { AuthModuleConfig, AUTH_MODULE_CONFIG } from './auth-config';
import { authConfigFactory, AuthConfigService } from './auth-config.service';
@@ -28,6 +28,7 @@ import { StorageService } from '../../common/services/storage.service';
import { provideRouter } from '@angular/router';
import { AUTH_ROUTES } from './auth.routes';
import { Authentication, AuthenticationInterceptor } from '@alfresco/adf-core/auth';
import { TimeSyncDateTimeProvider } from './time-sync-date-time-provider';
export const JWT_STORAGE_SERVICE = new InjectionToken<OAuthStorage>('JWT_STORAGE_SERVICE', {
providedIn: 'root',
@@ -54,6 +55,7 @@ export function provideCoreAuth(config: AuthModuleConfig = { useHash: false }):
provideOAuthClient(),
provideRouter(AUTH_ROUTES),
{ provide: OAuthStorage, useFactory: oauthStorageFactory },
{ provide: DateTimeProvider, useClass: TimeSyncDateTimeProvider },
AuthenticationService,
{
provide: AUTH_CONFIG,
+1
View File
@@ -22,3 +22,4 @@ export * from './redirect-auth.service';
export * from './view/authentication-confirmation/authentication-confirmation.component';
export * from './oidc-authentication.service';
export * from './web-crypto-jwks-validation-handler';
export * from './time-sync-date-time-provider';
@@ -0,0 +1,73 @@
/*!
* @license
* Copyright © 2005-2025 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 { TimeSyncDateTimeProvider } from './time-sync-date-time-provider';
import { TimeSyncService } from '../services/time-sync.service';
describe('TimeSyncDateTimeProvider', () => {
let provider: TimeSyncDateTimeProvider;
let timeSyncServiceSpy: jasmine.SpyObj<TimeSyncService>;
beforeEach(() => {
timeSyncServiceSpy = jasmine.createSpyObj('TimeSyncService', ['getCorrectedNow']);
TestBed.configureTestingModule({
providers: [TimeSyncDateTimeProvider, { provide: TimeSyncService, useValue: timeSyncServiceSpy }]
});
provider = TestBed.inject(TimeSyncDateTimeProvider);
});
describe('now', () => {
it('should return corrected timestamp from TimeSyncService', () => {
const correctedTime = 1728911640000;
timeSyncServiceSpy.getCorrectedNow.and.returnValue(correctedTime);
expect(provider.now()).toBe(correctedTime);
});
it('should delegate to TimeSyncService.getCorrectedNow', () => {
timeSyncServiceSpy.getCorrectedNow.and.returnValue(0);
provider.now();
expect(timeSyncServiceSpy.getCorrectedNow).toHaveBeenCalled();
});
});
describe('new', () => {
it('should return a Date object based on corrected timestamp', () => {
const correctedTime = 1728911640000;
timeSyncServiceSpy.getCorrectedNow.and.returnValue(correctedTime);
const result = provider.new();
expect(result).toBeInstanceOf(Date);
expect(result.getTime()).toBe(correctedTime);
});
it('should return a Date reflecting server-synchronized time', () => {
const correctedTime = 1728911640000; // (GMT): Monday, October 14, 2024 1:14:00 PM
timeSyncServiceSpy.getCorrectedNow.and.returnValue(correctedTime);
const result = provider.new();
expect(result.toISOString()).toBe('2024-10-14T13:14:00.000Z');
});
});
});
@@ -0,0 +1,40 @@
/*!
* @license
* Copyright © 2005-2025 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 { Injectable, inject } from '@angular/core';
import { DateTimeProvider } from 'angular-oauth2-oidc';
import { TimeSyncService } from '../services/time-sync.service';
/**
* Custom DateTimeProvider for angular-oauth2-oidc that uses the
* TimeSyncService to provide clock-drift-corrected timestamps.
*
* This ensures token validation within the OAuth library uses the
* server-synchronized time rather than the potentially drifted local clock.
*/
@Injectable()
export class TimeSyncDateTimeProvider extends DateTimeProvider {
private readonly timeSyncService = inject(TimeSyncService);
now(): number {
return this.timeSyncService.getCorrectedNow();
}
new(): Date {
return new Date(this.timeSyncService.getCorrectedNow());
}
}