backend-test-utils: mockCredentials refactor for ref validation, header, inline payload + tests
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -64,8 +64,8 @@ export namespace mockCredentials {
|
||||
userEntityRef?: string,
|
||||
): BackstageCredentials<BackstageUserPrincipal>;
|
||||
export namespace user {
|
||||
export function header(payload?: TokenPayload): string;
|
||||
export function token(payload?: TokenPayload): string;
|
||||
export function header(userEntityRef?: string): string;
|
||||
export function token(userEntityRef?: string): string;
|
||||
export type TokenPayload = {
|
||||
userEntityRef?: string;
|
||||
};
|
||||
|
||||
@@ -55,9 +55,7 @@ describe('MockAuthService', () => {
|
||||
).resolves.toEqual(mockCredentials.user(DEFAULT_MOCK_USER_ENTITY_REF));
|
||||
|
||||
await expect(
|
||||
auth.authenticate(
|
||||
mockCredentials.user.token({ userEntityRef: 'user:default/other' }),
|
||||
),
|
||||
auth.authenticate(mockCredentials.user.token('user:default/other')),
|
||||
).resolves.toEqual(mockCredentials.user('user:default/other'));
|
||||
});
|
||||
|
||||
|
||||
@@ -110,9 +110,7 @@ export class MockAuthService implements AuthService {
|
||||
return { token: mockCredentials.user.token() };
|
||||
}
|
||||
return {
|
||||
token: mockCredentials.user.token({
|
||||
userEntityRef: principal.userEntityRef,
|
||||
}),
|
||||
token: mockCredentials.user.token(principal.userEntityRef),
|
||||
};
|
||||
case 'service':
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* 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 { mockCredentials } from './mockCredentials';
|
||||
|
||||
describe('mockCredentials', () => {
|
||||
it('creates a mocked credentials object for a none principal', () => {
|
||||
expect(mockCredentials.none()).toEqual({
|
||||
$$type: '@backstage/BackstageCredentials',
|
||||
principal: { type: 'none' },
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a mocked credentials object for a user principal', () => {
|
||||
expect(mockCredentials.user()).toEqual({
|
||||
$$type: '@backstage/BackstageCredentials',
|
||||
principal: { type: 'user', userEntityRef: 'user:default/mock' },
|
||||
});
|
||||
|
||||
expect(mockCredentials.user('user:default/other')).toEqual({
|
||||
$$type: '@backstage/BackstageCredentials',
|
||||
principal: { type: 'user', userEntityRef: 'user:default/other' },
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a mocked credentials object for a service principal', () => {
|
||||
expect(mockCredentials.service()).toEqual({
|
||||
$$type: '@backstage/BackstageCredentials',
|
||||
principal: { type: 'service', subject: 'external:test-service' },
|
||||
});
|
||||
|
||||
expect(mockCredentials.service('plugin:other')).toEqual({
|
||||
$$type: '@backstage/BackstageCredentials',
|
||||
principal: { type: 'service', subject: 'plugin:other' },
|
||||
});
|
||||
});
|
||||
|
||||
it('creates user tokens and headers', () => {
|
||||
expect(mockCredentials.user.token()).toBe('mock-user-token');
|
||||
expect(mockCredentials.user.token('user:default/other')).toBe(
|
||||
'mock-user-token:{"userEntityRef":"user:default/other"}',
|
||||
);
|
||||
expect(mockCredentials.user.header()).toBe('Bearer mock-user-token');
|
||||
expect(mockCredentials.user.header('user:default/other')).toBe(
|
||||
'Bearer mock-user-token:{"userEntityRef":"user:default/other"}',
|
||||
);
|
||||
});
|
||||
|
||||
it('creates service tokens and headers', () => {
|
||||
expect(mockCredentials.service.token()).toBe('mock-service-token');
|
||||
expect(mockCredentials.service.token({ subject: 'external:other' })).toBe(
|
||||
'mock-service-token:{"subject":"external:other"}',
|
||||
);
|
||||
expect(
|
||||
mockCredentials.service.token({
|
||||
targetPluginId: 'other',
|
||||
}),
|
||||
).toBe('mock-service-token:{"targetPluginId":"other"}');
|
||||
expect(
|
||||
mockCredentials.service.token({
|
||||
subject: 'external:other',
|
||||
targetPluginId: 'other',
|
||||
}),
|
||||
).toBe(
|
||||
'mock-service-token:{"subject":"external:other","targetPluginId":"other"}',
|
||||
);
|
||||
// Object keys are reordered, ordering in the token should be stable
|
||||
expect(
|
||||
mockCredentials.service.token({
|
||||
targetPluginId: 'other',
|
||||
subject: 'external:other',
|
||||
}),
|
||||
).toBe(
|
||||
'mock-service-token:{"subject":"external:other","targetPluginId":"other"}',
|
||||
);
|
||||
|
||||
expect(mockCredentials.service.header()).toBe('Bearer mock-service-token');
|
||||
expect(mockCredentials.service.header({ subject: 'external:other' })).toBe(
|
||||
'Bearer mock-service-token:{"subject":"external:other"}',
|
||||
);
|
||||
expect(
|
||||
mockCredentials.service.header({
|
||||
targetPluginId: 'other',
|
||||
}),
|
||||
).toBe('Bearer mock-service-token:{"targetPluginId":"other"}');
|
||||
expect(
|
||||
mockCredentials.service.header({
|
||||
subject: 'external:other',
|
||||
targetPluginId: 'other',
|
||||
}),
|
||||
).toBe(
|
||||
'Bearer mock-service-token:{"subject":"external:other","targetPluginId":"other"}',
|
||||
);
|
||||
// Object keys are reordered, ordering in the token should be stable
|
||||
expect(
|
||||
mockCredentials.service.header({
|
||||
targetPluginId: 'other',
|
||||
subject: 'external:other',
|
||||
}),
|
||||
).toBe(
|
||||
'Bearer mock-service-token:{"subject":"external:other","targetPluginId":"other"}',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw on invalid user entity refs', () => {
|
||||
expect(() => mockCredentials.user('wrong')).toThrow(
|
||||
"Invalid user entity reference 'wrong', expected <kind>:<namespace>/<name>",
|
||||
);
|
||||
expect(() => mockCredentials.user('wr:ong')).toThrow(
|
||||
"Invalid user entity reference 'wr:ong', expected <kind>:<namespace>/<name>",
|
||||
);
|
||||
expect(() => mockCredentials.user('wr/ong')).toThrow(
|
||||
"Invalid user entity reference 'wr/ong', expected <kind>:<namespace>/<name>",
|
||||
);
|
||||
expect(() => mockCredentials.user('wr/o:ng')).toThrow(
|
||||
"Invalid user entity reference 'wr/o:ng', expected <kind>:<namespace>/<name>",
|
||||
);
|
||||
expect(() => mockCredentials.user('wr:/ong')).toThrow(
|
||||
"Invalid user entity reference 'wr:/ong', expected <kind>:<namespace>/<name>",
|
||||
);
|
||||
|
||||
expect(() => mockCredentials.user.token('wrong')).toThrow(
|
||||
"Invalid user entity reference 'wrong', expected <kind>:<namespace>/<name>",
|
||||
);
|
||||
expect(() => mockCredentials.user.header('wrong')).toThrow(
|
||||
"Invalid user entity reference 'wrong', expected <kind>:<namespace>/<name>",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -29,6 +29,14 @@ export const MOCK_USER_TOKEN_PREFIX = 'mock-user-token:';
|
||||
export const MOCK_SERVICE_TOKEN = 'mock-service-token';
|
||||
export const MOCK_SERVICE_TOKEN_PREFIX = 'mock-service-token:';
|
||||
|
||||
function validateUserEntityRef(ref: string) {
|
||||
if (!ref.match(/^.+:.+\/.+$/)) {
|
||||
throw new TypeError(
|
||||
`Invalid user entity reference '${ref}', expected <kind>:<namespace>/<name>`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@@ -51,6 +59,7 @@ export namespace mockCredentials {
|
||||
export function user(
|
||||
userEntityRef: string = DEFAULT_MOCK_USER_ENTITY_REF,
|
||||
): BackstageCredentials<BackstageUserPrincipal> {
|
||||
validateUserEntityRef(userEntityRef);
|
||||
return {
|
||||
$$type: '@backstage/BackstageCredentials',
|
||||
principal: { type: 'user', userEntityRef },
|
||||
@@ -71,9 +80,9 @@ export namespace mockCredentials {
|
||||
* into the token and forwarded to the credentials object when authenticated
|
||||
* by the mock auth service.
|
||||
*/
|
||||
export function token(payload?: TokenPayload): string {
|
||||
if (payload) {
|
||||
const { userEntityRef } = payload; // for fixed ordering
|
||||
export function token(userEntityRef?: string): string {
|
||||
if (userEntityRef) {
|
||||
validateUserEntityRef(userEntityRef);
|
||||
return `${MOCK_USER_TOKEN_PREFIX}${JSON.stringify({ userEntityRef })}`;
|
||||
}
|
||||
return MOCK_USER_TOKEN;
|
||||
@@ -84,8 +93,8 @@ export namespace mockCredentials {
|
||||
* provided it will be encoded into the token and forwarded to the
|
||||
* credentials object when authenticated by the mock auth service.
|
||||
*/
|
||||
export function header(payload?: TokenPayload): string {
|
||||
return `Bearer ${token(payload)}`;
|
||||
export function header(userEntityRef?: string): string {
|
||||
return `Bearer ${token(userEntityRef)}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user