feat(oidc): persist hashed OIDC tokens, authorization codes, and user consent in smartdata storage
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
|
||||
import { OidcAccessToken } from '../ts/reception/classes.oidcaccesstoken.js';
|
||||
import { OidcAuthorizationCode } from '../ts/reception/classes.oidcauthorizationcode.js';
|
||||
import { OidcRefreshToken } from '../ts/reception/classes.oidcrefreshtoken.js';
|
||||
import { OidcUserConsent } from '../ts/reception/classes.oidcuserconsent.js';
|
||||
|
||||
tap.test('stores authorization codes as hashes and marks them used', async () => {
|
||||
const authCode = new OidcAuthorizationCode();
|
||||
authCode.id = 'oidc-auth-code';
|
||||
authCode.data.codeHash = OidcAuthorizationCode.hashCode('plain-auth-code');
|
||||
|
||||
let saveCount = 0;
|
||||
(authCode as OidcAuthorizationCode & { save: () => Promise<void> }).save = async () => {
|
||||
saveCount++;
|
||||
};
|
||||
|
||||
expect(authCode.matchesCode('plain-auth-code')).toBeTrue();
|
||||
expect(authCode.matchesCode('wrong-code')).toBeFalse();
|
||||
|
||||
await authCode.markUsed();
|
||||
expect(authCode.data.used).toBeTrue();
|
||||
expect(saveCount).toEqual(1);
|
||||
});
|
||||
|
||||
tap.test('stores access tokens without plaintext persistence', async () => {
|
||||
const accessToken = new OidcAccessToken();
|
||||
accessToken.id = 'oidc-access-token';
|
||||
accessToken.data.tokenHash = OidcAccessToken.hashToken('plain-access-token');
|
||||
accessToken.data.expiresAt = Date.now() + 60_000;
|
||||
|
||||
expect(accessToken.matchesToken('plain-access-token')).toBeTrue();
|
||||
expect(accessToken.matchesToken('different-access-token')).toBeFalse();
|
||||
expect(accessToken.isExpired()).toBeFalse();
|
||||
});
|
||||
|
||||
tap.test('revokes persisted refresh tokens', async () => {
|
||||
const refreshToken = new OidcRefreshToken();
|
||||
refreshToken.id = 'oidc-refresh-token';
|
||||
refreshToken.data.tokenHash = OidcRefreshToken.hashToken('plain-refresh-token');
|
||||
refreshToken.data.expiresAt = Date.now() + 60_000;
|
||||
|
||||
let saveCount = 0;
|
||||
(refreshToken as OidcRefreshToken & { save: () => Promise<void> }).save = async () => {
|
||||
saveCount++;
|
||||
};
|
||||
|
||||
expect(refreshToken.matchesToken('plain-refresh-token')).toBeTrue();
|
||||
expect(refreshToken.data.revoked).toBeFalse();
|
||||
|
||||
await refreshToken.revoke();
|
||||
expect(refreshToken.data.revoked).toBeTrue();
|
||||
expect(saveCount).toEqual(1);
|
||||
});
|
||||
|
||||
tap.test('merges user consent scopes without duplicates', async () => {
|
||||
const consent = new OidcUserConsent();
|
||||
consent.id = 'oidc-consent';
|
||||
consent.data.userId = 'user-1';
|
||||
consent.data.clientId = 'client-1';
|
||||
consent.data.scopes = ['openid'];
|
||||
|
||||
let saveCount = 0;
|
||||
(consent as OidcUserConsent & { save: () => Promise<void> }).save = async () => {
|
||||
saveCount++;
|
||||
};
|
||||
|
||||
await consent.grantScopes(['openid', 'email', 'profile']);
|
||||
|
||||
expect(consent.data.scopes.sort()).toEqual(['email', 'openid', 'profile']);
|
||||
expect(consent.data.grantedAt).toBeGreaterThan(0);
|
||||
expect(consent.data.updatedAt).toBeGreaterThan(0);
|
||||
expect(saveCount).toEqual(1);
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
Reference in New Issue
Block a user