From ba0b8b45da1e5c0bbc0f9be7d924791a3ef99427 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 20 Apr 2024 16:14:01 +0200 Subject: [PATCH 1/3] backend-common: add allowDisabledTokenManager option for ServerTokenManager Signed-off-by: Patrik Oldsberg --- .changeset/smooth-garlics-behave.md | 5 +++ packages/backend-common/api-report.md | 3 +- .../src/tokens/ServerTokenManager.test.ts | 14 ++++++++ .../src/tokens/ServerTokenManager.ts | 35 ++++++++++++++++++- 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 .changeset/smooth-garlics-behave.md diff --git a/.changeset/smooth-garlics-behave.md b/.changeset/smooth-garlics-behave.md new file mode 100644 index 0000000000..ed972ae164 --- /dev/null +++ b/.changeset/smooth-garlics-behave.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Added option to `ServerTokenManager.fromConfig` that allows it to be instantiated in production without any configured keys. diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index 888bc1639c..f9e0d76aab 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -772,7 +772,7 @@ export class ServerTokenManager implements TokenManager { static fromConfig( config: Config, options: ServerTokenManagerOptions, - ): ServerTokenManager; + ): TokenManager; // (undocumented) getToken(): Promise<{ token: string; @@ -782,6 +782,7 @@ export class ServerTokenManager implements TokenManager { // @public export interface ServerTokenManagerOptions { + allowDisabledTokenManager?: boolean; logger: LoggerService; } diff --git a/packages/backend-common/src/tokens/ServerTokenManager.test.ts b/packages/backend-common/src/tokens/ServerTokenManager.test.ts index 7b9cf5965f..8870b4ed1c 100644 --- a/packages/backend-common/src/tokens/ServerTokenManager.test.ts +++ b/packages/backend-common/src/tokens/ServerTokenManager.test.ts @@ -301,6 +301,20 @@ describe('ServerTokenManager', () => { ), ).toThrow(); }); + + it('should throw errors when disabled', async () => { + const manager = ServerTokenManager.fromConfig(new ConfigReader({}), { + logger, + allowDisabledTokenManager: true, + }); + + await expect(manager.getToken()).rejects.toThrow( + 'Unable to generate legacy token', + ); + await expect(manager.authenticate('nah')).rejects.toThrow( + 'Unable to authenticate legacy token', + ); + }); }); describe('NODE_ENV === development', () => { diff --git a/packages/backend-common/src/tokens/ServerTokenManager.ts b/packages/backend-common/src/tokens/ServerTokenManager.ts index 453bfd7228..a62eb8de55 100644 --- a/packages/backend-common/src/tokens/ServerTokenManager.ts +++ b/packages/backend-common/src/tokens/ServerTokenManager.ts @@ -40,6 +40,23 @@ class NoopTokenManager implements TokenManager { async authenticate() {} } +/** + * A token manager that throws an error when trying to generate or authenticate tokens. + */ +class DisabledTokenManager implements TokenManager { + async getToken(): Promise<{ token: string }> { + throw new Error( + "Unable to generate legacy token, no legacy keys are configured in 'backend.auth.keys' or 'backend.auth.externalAccess'", + ); + } + + async authenticate() { + throw new AuthenticationError( + "Unable to authenticate legacy token, no legacy keys are configured in 'backend.auth.keys' or 'backend.auth.externalAccess'", + ); + } +} + /** * Options for {@link ServerTokenManager}. * @@ -50,6 +67,11 @@ export interface ServerTokenManagerOptions { * The logger to use. */ logger: LoggerService; + + /** + * Whether to disable the token manager if no keys are configured. + */ + allowDisabledTokenManager?: boolean; } /** @@ -73,7 +95,10 @@ export class ServerTokenManager implements TokenManager { return new NoopTokenManager(); } - static fromConfig(config: Config, options: ServerTokenManagerOptions) { + static fromConfig( + config: Config, + options: ServerTokenManagerOptions, + ): TokenManager { const oldSecrets = config .getOptionalConfigArray('backend.auth.keys') ?.map(c => c.getString('secret')); @@ -87,6 +112,14 @@ export class ServerTokenManager implements TokenManager { return new ServerTokenManager(secrets, options); } + // When using the new backend system with new auth services we instead rely + // on the new plugin auth and external access configurations. If no legacy + // keys are configured we disable the token manager completely, rather than + // requiring users to configure legacy keys. + if (options.allowDisabledTokenManager) { + return new DisabledTokenManager(); + } + if (process.env.NODE_ENV !== 'development') { throw new Error( 'You must configure at least one key in backend.auth.keys for production.', From dc8c5ddbaec0a791ce32411f3ae57c297a0a6d68 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 20 Apr 2024 16:16:48 +0200 Subject: [PATCH 2/3] backend-app-api: stop requiring keys to be configured for the token manager Signed-off-by: Patrik Oldsberg --- .changeset/hip-carrots-drive.md | 5 ++++ .../auth/DefaultAuthService.ts | 10 +++++-- .../tokenManagerServiceFactory.test.ts | 27 ++++++++----------- .../tokenManagerServiceFactory.ts | 1 + 4 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 .changeset/hip-carrots-drive.md diff --git a/.changeset/hip-carrots-drive.md b/.changeset/hip-carrots-drive.md new file mode 100644 index 0000000000..5852916b74 --- /dev/null +++ b/.changeset/hip-carrots-drive.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +The default `TokenManager` implementation no longer requires keys to be configured in production, but it will throw an errors when generating or authenticating tokens. The default `AuthService` implementation will now also provide additional context if such an error is throw when falling back to using the `TokenManager` service to generate tokens for outgoing requests. diff --git a/packages/backend-app-api/src/services/implementations/auth/DefaultAuthService.ts b/packages/backend-app-api/src/services/implementations/auth/DefaultAuthService.ts index cbb66891ba..dc76a8761b 100644 --- a/packages/backend-app-api/src/services/implementations/auth/DefaultAuthService.ts +++ b/packages/backend-app-api/src/services/implementations/auth/DefaultAuthService.ts @@ -23,7 +23,7 @@ import { BackstageServicePrincipal, BackstageUserPrincipal, } from '@backstage/backend-plugin-api'; -import { AuthenticationError } from '@backstage/errors'; +import { AuthenticationError, ForwardedError } from '@backstage/errors'; import { JsonObject } from '@backstage/types'; import { decodeJwt } from 'jose'; import { ExternalTokenHandler } from './external/ExternalTokenHandler'; @@ -151,7 +151,13 @@ export class DefaultAuthService implements AuthService { }); } // If the target plugin does not support the new auth service, fall back to using old token format - return this.tokenManager.getToken(); + return this.tokenManager.getToken().catch(error => { + throw new ForwardedError( + `Unable to generate legacy token for communication with the '${targetPluginId}' plugin. ` + + `You will typically encounter this error when attempting to call a plugin that does not exist, or is deployed with an old version of Backstage`, + error, + ); + }); case 'user': { const { token } = internalForward; if (!token) { diff --git a/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.test.ts b/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.test.ts index aca5211e2e..f603c6295e 100644 --- a/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.test.ts +++ b/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.test.ts @@ -14,25 +14,20 @@ * limitations under the License. */ -import { LoggerService } from '@backstage/backend-plugin-api'; -import { ConfigReader } from '@backstage/config'; import { tokenManagerServiceFactory } from './tokenManagerServiceFactory'; +import { ServiceFactoryTester } from '@backstage/backend-test-utils'; describe('tokenManagerFactory', () => { - it('should create managers that can share tokens in development', async () => { - (process.env as { NODE_ENV?: string }).NODE_ENV = 'development'; + it('should create a disabled manager without configuration', async () => { + const tokenManager = await ServiceFactoryTester.from( + tokenManagerServiceFactory, + ).get(); - const factory = tokenManagerServiceFactory() as any; - const deps = { - config: new ConfigReader({}), - logger: { warn() {} } as unknown as LoggerService, - }; - - const ctx = await factory.createRootContext?.(deps); - const manager1 = await factory.factory!(deps, ctx); - const manager2 = await factory.factory!(deps, ctx); - - const { token } = await manager1.getToken(); - await expect(manager2.authenticate(token)).resolves.toBeUndefined(); + await expect(tokenManager.authenticate('abc')).rejects.toThrow( + 'no legacy keys are configured', + ); + await expect(tokenManager.getToken()).rejects.toThrow( + 'no legacy keys are configured', + ); }); }); diff --git a/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.ts b/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.ts index 7417c18e23..cad1b06035 100644 --- a/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.ts @@ -30,6 +30,7 @@ export const tokenManagerServiceFactory = createServiceFactory({ createRootContext({ config, logger }) { return ServerTokenManager.fromConfig(config, { logger, + allowDisabledTokenManager: true, }); }, async factory(_deps, tokenManager) { From 5d7b8fa5dbaef583262e222b0b6aa1187bed0914 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 20 Apr 2024 16:17:04 +0200 Subject: [PATCH 3/3] app-config: removed todo plugin from OpenApi provider config Signed-off-by: Patrik Oldsberg --- app-config.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/app-config.yaml b/app-config.yaml index c016260bf8..9e5b5c468c 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -246,7 +246,6 @@ catalog: plugins: - catalog - search - - todo processors: ldapOrg: