auth-backend: migrate to support new auth services

Co-authored-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Carl-Erik Bergström <cbergstrom@spotify.com>
Co-authored-by: blam <ben@blam.sh>
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-02-15 18:59:33 +01:00
parent 72572b2fe1
commit 492fe83977
8 changed files with 109 additions and 16 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': minor
---
**BREAKING**: The `CatalogIdentityClient` constructor now also requires the `discovery` service to be forwarded from the plugin environment. This is part of the migration to support the new auth services, which has also been done for the `createRouter` function.
+14 -1
View File
@@ -8,6 +8,7 @@ import { AuthProviderFactory as AuthProviderFactory_2 } from '@backstage/plugin-
import { AuthProviderRouteHandlers as AuthProviderRouteHandlers_2 } from '@backstage/plugin-auth-node';
import { AuthResolverCatalogUserQuery as AuthResolverCatalogUserQuery_2 } from '@backstage/plugin-auth-node';
import { AuthResolverContext as AuthResolverContext_2 } from '@backstage/plugin-auth-node';
import { AuthService } from '@backstage/backend-plugin-api';
import { AwsAlbResult as AwsAlbResult_2 } from '@backstage/plugin-auth-backend-module-aws-alb-provider';
import { BackendFeature } from '@backstage/backend-plugin-api';
import { BackstageSignInResult } from '@backstage/plugin-auth-node';
@@ -17,11 +18,13 @@ import { ClientAuthResponse } from '@backstage/plugin-auth-node';
import { Config } from '@backstage/config';
import { CookieConfigurer as CookieConfigurer_2 } from '@backstage/plugin-auth-node';
import { decodeOAuthState } from '@backstage/plugin-auth-node';
import { DiscoveryService } from '@backstage/backend-plugin-api';
import { encodeOAuthState } from '@backstage/plugin-auth-node';
import { Entity } from '@backstage/catalog-model';
import express from 'express';
import { GcpIapResult as GcpIapResult_2 } from '@backstage/plugin-auth-backend-module-gcp-iap-provider';
import { GcpIapTokenInfo as GcpIapTokenInfo_2 } from '@backstage/plugin-auth-backend-module-gcp-iap-provider';
import { HttpAuthService } from '@backstage/backend-plugin-api';
import { LoggerService } from '@backstage/backend-plugin-api';
import { OAuth2ProxyResult as OAuth2ProxyResult_2 } from '@backstage/plugin-auth-backend-module-oauth2-proxy-provider';
import { OAuthEnvironmentHandler as OAuthEnvironmentHandler_2 } from '@backstage/plugin-auth-node';
@@ -117,7 +120,13 @@ export type BitbucketServerOAuthResult = {
// @public
export class CatalogIdentityClient {
constructor(options: { catalogApi: CatalogApi; tokenManager: TokenManager });
constructor(options: {
catalogApi: CatalogApi;
tokenManager: TokenManager;
discovery: DiscoveryService;
auth?: AuthService;
httpAuth?: HttpAuthService;
});
findUser(query: { annotations: Record<string, string> }): Promise<UserEntity>;
resolveCatalogMembership(query: {
entityRefs: string[];
@@ -642,6 +651,8 @@ export const readState: typeof decodeOAuthState;
// @public (undocumented)
export interface RouterOptions {
// (undocumented)
auth?: AuthService;
// (undocumented)
catalogApi?: CatalogApi;
// (undocumented)
@@ -653,6 +664,8 @@ export interface RouterOptions {
// (undocumented)
discovery: PluginEndpointDiscovery;
// (undocumented)
httpAuth?: HttpAuthService;
// (undocumented)
logger: LoggerService;
// (undocumented)
providerFactories?: ProviderFactories;
+4
View File
@@ -75,6 +75,10 @@ export const authPlugin = createBackendPlugin({
providerFactories: Object.fromEntries(providers),
disableDefaultProviderFactories: true,
});
httpRouter.addAuthPolicy({
path: '/',
allow: 'unauthenticated',
});
httpRouter.use(router);
},
});
@@ -48,6 +48,7 @@ describe('CatalogIdentityClient', () => {
catalogApi.getEntities.mockResolvedValueOnce({ items: [{} as UserEntity] });
tokenManager.getToken.mockResolvedValue({ token: 'my-token' });
const client = new CatalogIdentityClient({
discovery: {} as any,
catalogApi: catalogApi as Partial<CatalogApi> as CatalogApi,
tokenManager,
});
@@ -106,6 +107,7 @@ describe('CatalogIdentityClient', () => {
tokenManager.getToken.mockResolvedValue({ token: 'my-token' });
const client = new CatalogIdentityClient({
discovery: {} as any,
catalogApi: catalogApi as Partial<CatalogApi> as CatalogApi,
tokenManager,
});
@@ -14,7 +14,12 @@
* limitations under the License.
*/
import { LoggerService } from '@backstage/backend-plugin-api';
import {
AuthService,
DiscoveryService,
HttpAuthService,
LoggerService,
} from '@backstage/backend-plugin-api';
import { ConflictError, NotFoundError } from '@backstage/errors';
import { CatalogApi } from '@backstage/catalog-client';
import {
@@ -24,7 +29,10 @@ import {
stringifyEntityRef,
UserEntity,
} from '@backstage/catalog-model';
import { TokenManager } from '@backstage/backend-common';
import {
TokenManager,
createLegacyAuthAdapters,
} from '@backstage/backend-common';
/**
* A catalog client tailored for reading out identity data from the catalog.
@@ -33,11 +41,25 @@ import { TokenManager } from '@backstage/backend-common';
*/
export class CatalogIdentityClient {
private readonly catalogApi: CatalogApi;
private readonly tokenManager: TokenManager;
private readonly auth: AuthService;
constructor(options: { catalogApi: CatalogApi; tokenManager: TokenManager }) {
constructor(options: {
catalogApi: CatalogApi;
tokenManager: TokenManager;
discovery: DiscoveryService;
auth?: AuthService;
httpAuth?: HttpAuthService;
}) {
this.catalogApi = options.catalogApi;
this.tokenManager = options.tokenManager;
const { auth } = createLegacyAuthAdapters({
auth: options.auth,
httpAuth: options.httpAuth,
discovery: options.discovery,
tokenManager: options.tokenManager,
});
this.auth = auth;
}
/**
@@ -55,7 +77,11 @@ export class CatalogIdentityClient {
filter[`metadata.annotations.${key}`] = value;
}
const { token } = await this.tokenManager.getToken();
const { token } = await this.auth.getPluginRequestToken({
onBehalfOf: await this.auth.getOwnServiceCredentials(),
targetPluginId: 'catalog',
});
const { items } = await this.catalogApi.getEntities({ filter }, { token });
if (items.length !== 1) {
@@ -101,7 +127,12 @@ export class CatalogIdentityClient {
'metadata.namespace': ref.namespace,
'metadata.name': ref.name,
}));
const { token } = await this.tokenManager.getToken();
const { token } = await this.auth.getPluginRequestToken({
onBehalfOf: await this.auth.getOwnServiceCredentials(),
targetPluginId: 'catalog',
});
const entities = await this.catalogApi
.getEntities({ filter }, { token })
.then(r => r.items);
@@ -24,7 +24,12 @@ import {
stringifyEntityRef,
} from '@backstage/catalog-model';
import { ConflictError, InputError, NotFoundError } from '@backstage/errors';
import { LoggerService } from '@backstage/backend-plugin-api';
import {
AuthService,
DiscoveryService,
HttpAuthService,
LoggerService,
} from '@backstage/backend-plugin-api';
import { TokenIssuer } from '../../identity/types';
import { CatalogIdentityClient } from '../catalog';
import {
@@ -61,17 +66,24 @@ export class CatalogAuthResolverContext implements AuthResolverContext {
catalogApi: CatalogApi;
tokenIssuer: TokenIssuer;
tokenManager: TokenManager;
discovery: DiscoveryService;
auth: AuthService;
httpAuth: HttpAuthService;
}): CatalogAuthResolverContext {
const catalogIdentityClient = new CatalogIdentityClient({
catalogApi: options.catalogApi,
tokenManager: options.tokenManager,
discovery: options.discovery,
auth: options.auth,
httpAuth: options.httpAuth,
});
return new CatalogAuthResolverContext(
options.logger,
options.tokenIssuer,
catalogIdentityClient,
options.catalogApi,
options.tokenManager,
options.auth,
);
}
@@ -80,7 +92,7 @@ export class CatalogAuthResolverContext implements AuthResolverContext {
public readonly tokenIssuer: TokenIssuer,
public readonly catalogIdentityClient: CatalogIdentityClient,
private readonly catalogApi: CatalogApi,
private readonly tokenManager: TokenManager,
private readonly auth: AuthService,
) {}
async issueToken(params: TokenParams) {
@@ -90,7 +102,10 @@ export class CatalogAuthResolverContext implements AuthResolverContext {
async findCatalogUser(query: AuthResolverCatalogUserQuery) {
let result: Entity[] | Entity | undefined = undefined;
const { token } = await this.tokenManager.getToken();
const { token } = await this.auth.getPluginRequestToken({
onBehalfOf: await this.auth.getOwnServiceCredentials(),
targetPluginId: 'catalog',
});
if ('entityRef' in query) {
const entityRef = parseEntityRef(query.entityRef, {
+14 -3
View File
@@ -18,7 +18,11 @@ import {
PluginEndpointDiscovery,
TokenManager,
} from '@backstage/backend-common';
import { LoggerService } from '@backstage/backend-plugin-api';
import {
AuthService,
HttpAuthService,
LoggerService,
} from '@backstage/backend-plugin-api';
import { CatalogApi, CatalogClient } from '@backstage/catalog-client';
import { Config } from '@backstage/config';
import { NotFoundError, assertError } from '@backstage/errors';
@@ -41,6 +45,8 @@ export function bindProviderRouters(
config: Config;
logger: LoggerService;
discovery: PluginEndpointDiscovery;
auth: AuthService;
httpAuth: HttpAuthService;
tokenManager: TokenManager;
tokenIssuer: TokenIssuer;
catalogApi?: CatalogApi;
@@ -53,6 +59,8 @@ export function bindProviderRouters(
config,
logger,
discovery,
auth,
httpAuth,
tokenManager,
tokenIssuer,
catalogApi,
@@ -69,10 +77,10 @@ export function bindProviderRouters(
const provider = providerFactory({
providerId,
appUrl,
baseUrl: baseUrl,
baseUrl,
isOriginAllowed,
globalConfig: {
baseUrl: baseUrl,
baseUrl,
appUrl,
isOriginAllowed,
},
@@ -84,6 +92,9 @@ export function bindProviderRouters(
catalogApi ?? new CatalogClient({ discoveryApi: discovery }),
tokenIssuer,
tokenManager,
discovery,
auth,
httpAuth,
}),
});
+13 -1
View File
@@ -17,12 +17,17 @@
import express from 'express';
import Router from 'express-promise-router';
import cookieParser from 'cookie-parser';
import { LoggerService } from '@backstage/backend-plugin-api';
import {
AuthService,
HttpAuthService,
LoggerService,
} from '@backstage/backend-plugin-api';
import { defaultAuthProviderFactories } from '../providers';
import {
PluginDatabaseManager,
PluginEndpointDiscovery,
TokenManager,
createLegacyAuthAdapters,
} from '@backstage/backend-common';
import { NotFoundError } from '@backstage/errors';
import { CatalogApi } from '@backstage/catalog-client';
@@ -45,6 +50,8 @@ export interface RouterOptions {
config: Config;
discovery: PluginEndpointDiscovery;
tokenManager: TokenManager;
auth?: AuthService;
httpAuth?: HttpAuthService;
tokenFactoryAlgorithm?: string;
providerFactories?: ProviderFactories;
disableDefaultProviderFactories?: boolean;
@@ -63,6 +70,9 @@ export async function createRouter(
tokenFactoryAlgorithm,
providerFactories = {},
} = options;
const { auth, httpAuth } = createLegacyAuthAdapters(options);
const router = Router();
const appUrl = config.getString('app.baseUrl');
@@ -136,6 +146,8 @@ export async function createRouter(
baseUrl: authUrl,
tokenIssuer,
...options,
auth,
httpAuth,
});
bindOidcRouter(router, {