Merge pull request #22765 from drodil/auth_resolver_override

feat: allow overriding default ownership resolving
This commit is contained in:
Patrik Oldsberg
2024-04-23 16:44:50 +02:00
committed by GitHub
11 changed files with 111 additions and 8 deletions
+3
View File
@@ -3,6 +3,7 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { AuthOwnershipResolver } from '@backstage/plugin-auth-node';
import { AuthProviderConfig as AuthProviderConfig_2 } from '@backstage/plugin-auth-node';
import { AuthProviderFactory as AuthProviderFactory_2 } from '@backstage/plugin-auth-node';
import { AuthProviderRouteHandlers as AuthProviderRouteHandlers_2 } from '@backstage/plugin-auth-node';
@@ -665,6 +666,8 @@ export interface RouterOptions {
// (undocumented)
logger: LoggerService;
// (undocumented)
ownershipResolver?: AuthOwnershipResolver;
// (undocumented)
providerFactories?: ProviderFactories;
// (undocumented)
tokenFactoryAlgorithm?: string;
+13
View File
@@ -19,6 +19,8 @@ import {
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import {
authOwnershipResolutionExtensionPoint,
AuthOwnershipResolver,
AuthProviderFactory,
authProvidersExtensionPoint,
} from '@backstage/plugin-auth-node';
@@ -34,6 +36,7 @@ export const authPlugin = createBackendPlugin({
pluginId: 'auth',
register(reg) {
const providers = new Map<string, AuthProviderFactory>();
let ownershipResolver: AuthOwnershipResolver | undefined = undefined;
reg.registerExtensionPoint(authProvidersExtensionPoint, {
registerProvider({ providerId, factory }) {
@@ -46,6 +49,15 @@ export const authPlugin = createBackendPlugin({
},
});
reg.registerExtensionPoint(authOwnershipResolutionExtensionPoint, {
setAuthOwnershipResolver(resolver) {
if (ownershipResolver) {
throw new Error('Auth ownership resolver is already set');
}
ownershipResolver = resolver;
},
});
reg.registerInit({
deps: {
httpRouter: coreServices.httpRouter,
@@ -80,6 +92,7 @@ export const authPlugin = createBackendPlugin({
catalogApi,
providerFactories: Object.fromEntries(providers),
disableDefaultProviderFactories: true,
ownershipResolver,
});
httpRouter.addAuthPolicy({
path: '/',
@@ -31,12 +31,13 @@ import {
LoggerService,
} from '@backstage/backend-plugin-api';
import { TokenIssuer } from '../../identity/types';
import { CatalogIdentityClient } from '../catalog';
import {
AuthOwnershipResolver,
AuthResolverCatalogUserQuery,
AuthResolverContext,
TokenParams,
} from '@backstage/plugin-auth-node';
import { CatalogIdentityClient } from '../catalog';
/**
* Uses the default ownership resolution logic to return an array
@@ -69,6 +70,7 @@ export class CatalogAuthResolverContext implements AuthResolverContext {
discovery: DiscoveryService;
auth: AuthService;
httpAuth: HttpAuthService;
ownershipResolver?: AuthOwnershipResolver;
}): CatalogAuthResolverContext {
const catalogIdentityClient = new CatalogIdentityClient({
catalogApi: options.catalogApi,
@@ -84,6 +86,7 @@ export class CatalogAuthResolverContext implements AuthResolverContext {
catalogIdentityClient,
options.catalogApi,
options.auth,
options.ownershipResolver,
);
}
@@ -93,6 +96,7 @@ export class CatalogAuthResolverContext implements AuthResolverContext {
public readonly catalogIdentityClient: CatalogIdentityClient,
private readonly catalogApi: CatalogApi,
private readonly auth: AuthService,
private readonly ownershipResolver?: AuthOwnershipResolver,
) {}
async issueToken(params: TokenParams) {
@@ -160,12 +164,19 @@ export class CatalogAuthResolverContext implements AuthResolverContext {
async signInWithCatalogUser(query: AuthResolverCatalogUserQuery) {
const { entity } = await this.findCatalogUser(query);
const ownershipRefs = getDefaultOwnershipEntityRefs(entity);
let ent: string[];
if (this.ownershipResolver) {
const { ownershipEntityRefs } =
await this.ownershipResolver.resolveOwnershipEntityRefs(entity);
ent = ownershipEntityRefs;
} else {
ent = getDefaultOwnershipEntityRefs(entity);
}
const token = await this.tokenIssuer.issueToken({
claims: {
sub: stringifyEntityRef(entity),
ent: ownershipRefs,
ent,
},
});
return { token };
+8 -2
View File
@@ -25,8 +25,11 @@ import {
} from '@backstage/backend-plugin-api';
import { CatalogApi, CatalogClient } from '@backstage/catalog-client';
import { Config } from '@backstage/config';
import { NotFoundError, assertError } from '@backstage/errors';
import { AuthProviderFactory } from '@backstage/plugin-auth-node';
import { assertError, NotFoundError } from '@backstage/errors';
import {
AuthOwnershipResolver,
AuthProviderFactory,
} from '@backstage/plugin-auth-node';
import express from 'express';
import Router from 'express-promise-router';
import { Minimatch } from 'minimatch';
@@ -49,6 +52,7 @@ export function bindProviderRouters(
httpAuth: HttpAuthService;
tokenManager: TokenManager;
tokenIssuer: TokenIssuer;
ownershipResolver?: AuthOwnershipResolver;
catalogApi?: CatalogApi;
},
) {
@@ -64,6 +68,7 @@ export function bindProviderRouters(
tokenManager,
tokenIssuer,
catalogApi,
ownershipResolver,
} = options;
const providersConfig = config.getOptionalConfig('auth.providers');
@@ -95,6 +100,7 @@ export function bindProviderRouters(
discovery,
auth,
httpAuth,
ownershipResolver,
}),
});
+5 -3
View File
@@ -23,15 +23,16 @@ import {
LoggerService,
} from '@backstage/backend-plugin-api';
import { defaultAuthProviderFactories } from '../providers';
import { AuthOwnershipResolver } from '@backstage/plugin-auth-node';
import {
createLegacyAuthAdapters,
PluginDatabaseManager,
PluginEndpointDiscovery,
TokenManager,
createLegacyAuthAdapters,
} from '@backstage/backend-common';
import { NotFoundError } from '@backstage/errors';
import { CatalogApi } from '@backstage/catalog-client';
import { bindOidcRouter, TokenFactory, KeyStores } from '../identity';
import { bindOidcRouter, KeyStores, TokenFactory } from '../identity';
import session from 'express-session';
import connectSessionKnex from 'connect-session-knex';
import passport from 'passport';
@@ -41,7 +42,7 @@ import { TokenIssuer } from '../identity/types';
import { StaticTokenIssuer } from '../identity/StaticTokenIssuer';
import { StaticKeyStore } from '../identity/StaticKeyStore';
import { Config } from '@backstage/config';
import { ProviderFactories, bindProviderRouters } from '../providers/router';
import { bindProviderRouters, ProviderFactories } from '../providers/router';
/** @public */
export interface RouterOptions {
@@ -56,6 +57,7 @@ export interface RouterOptions {
providerFactories?: ProviderFactories;
disableDefaultProviderFactories?: boolean;
catalogApi?: CatalogApi;
ownershipResolver?: AuthOwnershipResolver;
}
/** @public */
+17
View File
@@ -21,6 +21,23 @@ import { Strategy } from 'passport';
import { ZodSchema } from 'zod';
import { ZodTypeDef } from 'zod';
// @public (undocumented)
export interface AuthOwnershipResolutionExtensionPoint {
// (undocumented)
setAuthOwnershipResolver(ownershipResolver: AuthOwnershipResolver): void;
}
// @public (undocumented)
export const authOwnershipResolutionExtensionPoint: ExtensionPoint<AuthOwnershipResolutionExtensionPoint>;
// @public
export interface AuthOwnershipResolver {
// (undocumented)
resolveOwnershipEntityRefs(entity: Entity): Promise<{
ownershipEntityRefs: string[];
}>;
}
// @public @deprecated (undocumented)
export type AuthProviderConfig = {
baseUrl: string;
@@ -0,0 +1,28 @@
/*
* Copyright 2023 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 { AuthOwnershipResolver } from '../types';
import { createExtensionPoint } from '@backstage/backend-plugin-api';
/** @public */
export interface AuthOwnershipResolutionExtensionPoint {
setAuthOwnershipResolver(ownershipResolver: AuthOwnershipResolver): void;
}
/** @public */
export const authOwnershipResolutionExtensionPoint =
createExtensionPoint<AuthOwnershipResolutionExtensionPoint>({
id: 'auth.ownershipResolution',
});
@@ -19,3 +19,8 @@ export {
type AuthProviderRegistrationOptions,
type AuthProvidersExtensionPoint,
} from './AuthProvidersExtensionPoint';
export {
authOwnershipResolutionExtensionPoint,
type AuthOwnershipResolutionExtensionPoint,
} from './AuthOwnershipResolutionExtensionPoint';
+1
View File
@@ -43,5 +43,6 @@ export type {
SignInInfo,
SignInResolver,
TokenParams,
AuthOwnershipResolver,
} from './types';
export { tokenTypes } from './types';
+11
View File
@@ -163,6 +163,17 @@ export type AuthResolverContext = {
): Promise<BackstageSignInResult>;
};
/**
* Resolver interface for resolving the ownership entity references for entity
*
* @public
*/
export interface AuthOwnershipResolver {
resolveOwnershipEntityRefs(
entity: Entity,
): Promise<{ ownershipEntityRefs: string[] }>;
}
/**
* Any Auth provider needs to implement this interface which handles the routes in the
* auth backend. Any auth API requests from the frontend reaches these methods.