auth: convert permission-backend to the new auth services
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import { BackendFeature } from '@backstage/backend-plugin-api';
|
||||
import { BackstageCredentials } from '@backstage/backend-plugin-api';
|
||||
import { BackstageNonePrincipal } from '@backstage/backend-plugin-api';
|
||||
import { BackstageServicePrincipal } from '@backstage/backend-plugin-api';
|
||||
import { BackstageUserInfo } from '@backstage/backend-plugin-api';
|
||||
import { BackstageUserPrincipal } from '@backstage/backend-plugin-api';
|
||||
import { CacheService } from '@backstage/backend-plugin-api';
|
||||
import { DatabaseService } from '@backstage/backend-plugin-api';
|
||||
@@ -37,6 +38,7 @@ import { ServiceFactory } from '@backstage/backend-plugin-api';
|
||||
import { ServiceRef } from '@backstage/backend-plugin-api';
|
||||
import { TokenManagerService } from '@backstage/backend-plugin-api';
|
||||
import { UrlReaderService } from '@backstage/backend-plugin-api';
|
||||
import { UserInfoService } from '@backstage/backend-plugin-api';
|
||||
|
||||
// @public
|
||||
export function createMockDirectory(
|
||||
@@ -316,6 +318,17 @@ export namespace mockServices {
|
||||
partialImpl?: Partial<UrlReaderService> | undefined,
|
||||
) => ServiceMock<UrlReaderService>;
|
||||
}
|
||||
export function userInfo(
|
||||
customInfo?: Partial<BackstageUserInfo>,
|
||||
): UserInfoService;
|
||||
// (undocumented)
|
||||
export namespace userInfo {
|
||||
const factory: () => ServiceFactory<UserInfoService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<UserInfoService> | undefined,
|
||||
) => ServiceMock<UserInfoService>;
|
||||
}
|
||||
}
|
||||
|
||||
// @public
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 { MockUserInfoService } from './MockUserInfoService';
|
||||
import { mockCredentials } from './mockCredentials';
|
||||
|
||||
describe('MockUserInfoService', () => {
|
||||
it('works without constructor parameters', async () => {
|
||||
const service = new MockUserInfoService();
|
||||
const user = mockCredentials.user();
|
||||
await expect(service.getUserInfo(user)).resolves.toEqual({
|
||||
userEntityRef: user.principal.userEntityRef,
|
||||
ownershipEntityRefs: [user.principal.userEntityRef],
|
||||
});
|
||||
});
|
||||
|
||||
it('works with custom constructor parameters', async () => {
|
||||
const service = new MockUserInfoService({
|
||||
userEntityRef: 'user:default/not-the-mock-1',
|
||||
ownershipEntityRefs: ['user:default/not-the-mock-2'],
|
||||
});
|
||||
const user = mockCredentials.user();
|
||||
await expect(service.getUserInfo(user)).resolves.toEqual({
|
||||
userEntityRef: 'user:default/not-the-mock-1',
|
||||
ownershipEntityRefs: ['user:default/not-the-mock-2'],
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects non-users', async () => {
|
||||
const service = new MockUserInfoService();
|
||||
await expect(
|
||||
service.getUserInfo(mockCredentials.none()),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"User info not available for principal type 'none'"`,
|
||||
);
|
||||
await expect(
|
||||
service.getUserInfo(mockCredentials.service()),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"User info not available for principal type 'service'"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 {
|
||||
BackstageCredentials,
|
||||
BackstageNonePrincipal,
|
||||
BackstageServicePrincipal,
|
||||
BackstageUserInfo,
|
||||
BackstageUserPrincipal,
|
||||
UserInfoService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { InputError } from '@backstage/errors';
|
||||
|
||||
/** @internal */
|
||||
export class MockUserInfoService implements UserInfoService {
|
||||
private readonly customInfo: Partial<BackstageUserInfo>;
|
||||
|
||||
constructor(customInfo?: Partial<BackstageUserInfo>) {
|
||||
this.customInfo = customInfo ?? {};
|
||||
}
|
||||
|
||||
async getUserInfo(
|
||||
credentials: BackstageCredentials,
|
||||
): Promise<BackstageUserInfo> {
|
||||
const principal = credentials.principal as
|
||||
| BackstageUserPrincipal
|
||||
| BackstageServicePrincipal
|
||||
| BackstageNonePrincipal;
|
||||
|
||||
if (principal.type !== 'user') {
|
||||
throw new InputError(
|
||||
`User info not available for principal type '${principal.type}'`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
userEntityRef: principal.userEntityRef,
|
||||
ownershipEntityRefs: [principal.userEntityRef],
|
||||
...this.customInfo,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,8 @@ import {
|
||||
DiscoveryService,
|
||||
HttpAuthService,
|
||||
BackstageCredentials,
|
||||
BackstageUserInfo,
|
||||
UserInfoService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import {
|
||||
cacheServiceFactory,
|
||||
@@ -49,6 +51,7 @@ import { MockRootLoggerService } from './MockRootLoggerService';
|
||||
import { MockAuthService } from './MockAuthService';
|
||||
import { MockHttpAuthService } from './MockHttpAuthService';
|
||||
import { mockCredentials } from './mockCredentials';
|
||||
import { MockUserInfoService } from './MockUserInfoService';
|
||||
|
||||
/** @internal */
|
||||
function simpleFactory<
|
||||
@@ -272,6 +275,37 @@ export namespace mockServices {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock implementation of the `UserInfoService`.
|
||||
*
|
||||
* By default it extracts the user's entity ref from a user principal and
|
||||
* returns that as the only ownership entity ref, but this can be overridden
|
||||
* by passing in a custom set of user info.
|
||||
*/
|
||||
export function userInfo(
|
||||
customInfo?: Partial<BackstageUserInfo>,
|
||||
): UserInfoService {
|
||||
return new MockUserInfoService(customInfo);
|
||||
}
|
||||
export namespace userInfo {
|
||||
/**
|
||||
* Creates a mock service factory for the `UserInfoService`.
|
||||
*
|
||||
* By default it extracts the user's entity ref from a user principal and
|
||||
* returns that as the only ownership entity ref.
|
||||
*/
|
||||
export const factory = createServiceFactory({
|
||||
service: coreServices.userInfo,
|
||||
deps: {},
|
||||
factory() {
|
||||
return new MockUserInfoService();
|
||||
},
|
||||
});
|
||||
export const mock = simpleMock(coreServices.userInfo, () => ({
|
||||
getUserInfo: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
// TODO(Rugvip): Not all core services have implementations available here yet.
|
||||
// some may need a bit more refactoring for it to be simpler to
|
||||
// re-implement functioning mock versions here.
|
||||
@@ -284,12 +318,14 @@ export namespace mockServices {
|
||||
withOptions: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
export namespace database {
|
||||
export const factory = databaseServiceFactory;
|
||||
export const mock = simpleMock(coreServices.database, () => ({
|
||||
getClient: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
export namespace httpRouter {
|
||||
export const factory = httpRouterServiceFactory;
|
||||
export const mock = simpleMock(coreServices.httpRouter, () => ({
|
||||
@@ -297,12 +333,14 @@ export namespace mockServices {
|
||||
addAuthPolicy: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
export namespace rootHttpRouter {
|
||||
export const factory = rootHttpRouterServiceFactory;
|
||||
export const mock = simpleMock(coreServices.rootHttpRouter, () => ({
|
||||
use: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
export namespace lifecycle {
|
||||
export const factory = lifecycleServiceFactory;
|
||||
export const mock = simpleMock(coreServices.lifecycle, () => ({
|
||||
@@ -310,6 +348,7 @@ export namespace mockServices {
|
||||
addStartupHook: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
export namespace logger {
|
||||
export const factory = loggerServiceFactory;
|
||||
export const mock = simpleMock(coreServices.logger, () => ({
|
||||
@@ -320,6 +359,7 @@ export namespace mockServices {
|
||||
warn: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
export namespace permissions {
|
||||
export const factory = permissionsServiceFactory;
|
||||
export const mock = simpleMock(coreServices.permissions, () => ({
|
||||
@@ -327,6 +367,7 @@ export namespace mockServices {
|
||||
authorizeConditional: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
export namespace rootLifecycle {
|
||||
export const factory = rootLifecycleServiceFactory;
|
||||
export const mock = simpleMock(coreServices.rootLifecycle, () => ({
|
||||
@@ -334,6 +375,7 @@ export namespace mockServices {
|
||||
addStartupHook: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
export namespace scheduler {
|
||||
export const factory = schedulerServiceFactory;
|
||||
export const mock = simpleMock(coreServices.scheduler, () => ({
|
||||
@@ -343,6 +385,7 @@ export namespace mockServices {
|
||||
triggerTask: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
export namespace urlReader {
|
||||
export const factory = urlReaderServiceFactory;
|
||||
export const mock = simpleMock(coreServices.urlReader, () => ({
|
||||
|
||||
@@ -80,6 +80,7 @@ export const defaultServiceFactories = [
|
||||
mockServices.rootLogger.factory(),
|
||||
mockServices.scheduler.factory(),
|
||||
mockServices.tokenManager.factory(),
|
||||
mockServices.userInfo.factory(),
|
||||
mockServices.urlReader.factory(),
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user