From f7d1ff30e53583a09a1fc49ba258e9af7471b2dc Mon Sep 17 00:00:00 2001 From: "Nithin S. Sabu" Date: Wed, 6 Nov 2024 23:38:31 +0100 Subject: [PATCH] feat(authorization): add bearer token authorization --- .../oauth/OAuthProvider.unit.spec.ts | 33 ++++++++++++++++++ src/lib/Configuration.ts | 13 +++++-- src/lib/ConstructOAuthProvider.ts | 4 +++ src/oauth/lib/BearerAuthProvider.ts | 34 +++++++++++++++++++ 4 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 src/oauth/lib/BearerAuthProvider.ts diff --git a/src/__tests__/oauth/OAuthProvider.unit.spec.ts b/src/__tests__/oauth/OAuthProvider.unit.spec.ts index 66331b94..fbee122b 100644 --- a/src/__tests__/oauth/OAuthProvider.unit.spec.ts +++ b/src/__tests__/oauth/OAuthProvider.unit.spec.ts @@ -613,4 +613,37 @@ describe('OAuthProvider', () => { expect(res).toBeTruthy() }) }) + + it('Can use Bearer Token Auth as a strategy', async () => { + const server = http.createServer((req, res) => { + const authHeader = req.headers['authorization'] + + if (!authHeader || authHeader !== 'Bearer mysecrettoken') { + res.statusCode = 401 + res.setHeader('WWW-Authenticate', 'Bearer realm="example"') + res.end('Access denied') + } else { + res.end('Access granted') + } + }) + + server.listen(3033) + + const oAuthProvider = constructOAuthProvider({ + CAMUNDA_AUTH_STRATEGY: 'BEARER', + CAMUNDA_OAUTH_TOKEN: 'mysecrettoken', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any) + const token = await oAuthProvider.getToken('ZEEBE') + await got + .get('http://localhost:3033', { + headers: { + Authorization: 'Bearer ' + token, + }, + }) + .then((res) => { + server.close() + expect(res).toBeTruthy() + }) + }) }) diff --git a/src/lib/Configuration.ts b/src/lib/Configuration.ts index 60f6893d..33fcf565 100644 --- a/src/lib/Configuration.ts +++ b/src/lib/Configuration.ts @@ -62,6 +62,11 @@ const getMainEnv = () => type: 'string', optional: true, }, + /** The OAuth token (used for CAMUNDA_AUTH_STRATEGY "BEARER") */ + CAMUNDA_OAUTH_TOKEN: { + type: 'string', + optional: true, + }, /** Optional scope parameter for OAuth (needed by some OIDC) */ CAMUNDA_TOKEN_SCOPE: { type: 'string', @@ -195,7 +200,7 @@ const getMainEnv = () => }, CAMUNDA_AUTH_STRATEGY: { type: 'string', - choices: ['BASIC', 'OAUTH', 'NONE'], + choices: ['BASIC', 'OAUTH', 'BEARER', 'NONE'], default: 'OAUTH', }, }) @@ -367,8 +372,9 @@ const getEnv = () => ({ // Helper type for enforcing array contents to match an object's keys // eslint-disable-next-line @typescript-eslint/no-explicit-any -type EnforceArrayContent = - T extends Array ? T : never +type EnforceArrayContent = T extends Array + ? T + : never // Function to create a complete keys array, enforcing completeness at compile time // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -396,6 +402,7 @@ export const CamundaEnvironmentVariableDictionary = 'CAMUNDA_OPTIMIZE_OAUTH_AUDIENCE', 'CAMUNDA_OAUTH_DISABLED', 'CAMUNDA_OAUTH_URL', + 'CAMUNDA_OAUTH_TOKEN', 'CAMUNDA_SECURE_CONNECTION', 'CAMUNDA_TASKLIST_BASE_URL', 'CAMUNDA_TASKLIST_OAUTH_AUDIENCE', diff --git a/src/lib/ConstructOAuthProvider.ts b/src/lib/ConstructOAuthProvider.ts index 23a23004..92548ef6 100644 --- a/src/lib/ConstructOAuthProvider.ts +++ b/src/lib/ConstructOAuthProvider.ts @@ -2,6 +2,7 @@ import debug from 'debug' import { NullAuthProvider, OAuthProvider } from '../oauth' import { BasicAuthProvider } from '../oauth/lib/BasicAuthProvider' +import { BearerAuthProvider } from '../oauth/lib/BearerAuthProvider' import { CamundaPlatform8Configuration } from './Configuration' @@ -20,6 +21,9 @@ export function constructOAuthProvider(config: CamundaPlatform8Configuration) { if (config.CAMUNDA_AUTH_STRATEGY === 'BASIC') { trace(`Using Basic Auth`) return new BasicAuthProvider({ config }) + } else if (config.CAMUNDA_AUTH_STRATEGY === 'BEARER') { + trace(`Using Bearer Token`) + return new BearerAuthProvider({ config }) } else { trace(`Using OAuth`) return new OAuthProvider({ config }) diff --git a/src/oauth/lib/BearerAuthProvider.ts b/src/oauth/lib/BearerAuthProvider.ts new file mode 100644 index 00000000..e29d8068 --- /dev/null +++ b/src/oauth/lib/BearerAuthProvider.ts @@ -0,0 +1,34 @@ +import { debug } from 'debug' + +import { + CamundaEnvironmentConfigurator, + CamundaPlatform8Configuration, + DeepPartial, + RequireConfiguration, +} from '../../lib' +import { IOAuthProvider } from '../index' + +import { TokenGrantAudienceType } from './IOAuthProvider' + +export class BearerAuthProvider implements IOAuthProvider { + private bearerToken: string + + constructor(options?: { + config?: DeepPartial + }) { + const config = CamundaEnvironmentConfigurator.mergeConfigWithEnvironment( + options?.config ?? {} + ) + + this.bearerToken = RequireConfiguration( + config.CAMUNDA_OAUTH_TOKEN, + 'CAMUNDA_OAUTH_TOKEN' + ) + } + + public async getToken(audienceType: TokenGrantAudienceType): Promise { + debug(`Token request for ${audienceType}`) + + return Promise.resolve(this.bearerToken) + } +}