From a209feffdea47f0992f17a7c0265535614143dfe Mon Sep 17 00:00:00 2001 From: Peter Somogyvari Date: Thu, 27 May 2021 16:24:32 -0700 Subject: [PATCH] fix(cmd-api-server): config-service example - authorization JSON The custom formatter that was introduced the parse the JSON config for the authorizer was causing problems. This was overlooked at the time of the implementation of the authz feature because Peter (yours truly) is an idiot but also to a smaller extent because there was no automated test coverage for this specific issue which this commit is now rectifying by adding a new test case. Longer term we should look into using a different configuration parsing library that has more flexibility on how to handle JSON and validations around it. There was a second bug masked by the first which is that the "algorithms" array property of the express-jwt middleware options was also not being used correctly, but to get to that first the initial bug with the parsing had to be fixed. Signed-off-by: Peter Somogyvari --- .../main/typescript/config/config-service.ts | 46 ++++++++----------- ...ig-service-example-config-validity.test.ts | 34 ++++++++++++++ 2 files changed, 53 insertions(+), 27 deletions(-) create mode 100644 packages/cactus-cmd-api-server/src/test/typescript/unit/config/config-service-example-config-validity.test.ts diff --git a/packages/cactus-cmd-api-server/src/main/typescript/config/config-service.ts b/packages/cactus-cmd-api-server/src/main/typescript/config/config-service.ts index dda8a7e4fa..ebabfed631 100644 --- a/packages/cactus-cmd-api-server/src/main/typescript/config/config-service.ts +++ b/packages/cactus-cmd-api-server/src/main/typescript/config/config-service.ts @@ -4,11 +4,11 @@ import convict, { Schema, Config, SchemaObj } from "convict"; import { ipaddress } from "convict-format-with-validator"; import { v4 as uuidV4 } from "uuid"; import { JWK, JWS } from "jose"; +import type { Options as ExpressJwtOptions } from "express-jwt"; import { LoggerProvider, Logger, LogLevelDesc, - Strings, } from "@hyperledger/cactus-common"; import { ConsortiumDatabase, @@ -108,19 +108,7 @@ export class ConfigService { authorizationConfigJson: { doc: "The JSON string to deserialize when configuring authorization.", default: null as IAuthorizationConfig | null, - format: (json: string) => { - if (Strings.isString(json)) { - ConfigService.formatNonBlankString(json); - try { - const authzConf = JSON.parse(json) as IAuthorizationConfig; - return authzConf; - } catch (ex) { - throw new Error(`AUTHORIZATION_CONFIG_JSON invalid JSON`); - } - } else { - return json; - } - }, + format: Object, env: "AUTHORIZATION_CONFIG_JSON", arg: "authorization-config-json", }, @@ -513,21 +501,25 @@ export class ConfigService { const jwtSecret = uuidV4(); + const expressJwtOptions: ExpressJwtOptions = { + secret: jwtSecret, + algorithms: ["RS256"], + audience: "org.hyperledger.cactus.jwt.audience", + issuer: "org.hyperledger.cactus.jwt.issuer", + }; + + const authorizationConfigJson: IAuthorizationConfig = { + socketIoPath: Constants.SocketIoConnectionPathV1, + unprotectedEndpointExemptions: [], + socketIoJwtOptions: { + secret: jwtSecret, + }, + expressJwtOptions, + }; + return { authorizationProtocol: AuthorizationProtocol.JSON_WEB_TOKEN, - authorizationConfigJson: { - socketIoPath: Constants.SocketIoConnectionPathV1, - unprotectedEndpointExemptions: [], - socketIoJwtOptions: { - secret: jwtSecret, - }, - expressJwtOptions: { - secret: jwtSecret, - algorithms: ["RS256"], - audience: "org.hyperledger.cactus.jwt.audience", - issuer: "org.hyperledger.cactus.jwt.issuer", - }, - }, + authorizationConfigJson, configFile: ".config.json", cactusNodeId: uuidV4(), consortiumId: uuidV4(), diff --git a/packages/cactus-cmd-api-server/src/test/typescript/unit/config/config-service-example-config-validity.test.ts b/packages/cactus-cmd-api-server/src/test/typescript/unit/config/config-service-example-config-validity.test.ts new file mode 100644 index 0000000000..e73417d289 --- /dev/null +++ b/packages/cactus-cmd-api-server/src/test/typescript/unit/config/config-service-example-config-validity.test.ts @@ -0,0 +1,34 @@ +import { LoggerProvider } from "@hyperledger/cactus-common"; +import test, { Test } from "tape-promise/tape"; + +import { IAuthorizationConfig } from "../../../../main/typescript/public-api"; +import { ApiServer } from "../../../../main/typescript/public-api"; +import { ConfigService } from "../../../../main/typescript/public-api"; + +test("Generates valid example config for the API server", async (t: Test) => { + const configService = new ConfigService(); + t.ok(configService, "Instantiated ConfigService truthy OK"); + + const exampleConfig = configService.newExampleConfig(); + t.ok(exampleConfig, "configService.newExampleConfig() truthy OK"); + + // FIXME - this hack should not be necessary, we need to re-think how we + // do configuration parsing. The convict library may not be the path forward. + exampleConfig.authorizationConfigJson = (JSON.stringify( + exampleConfig.authorizationConfigJson, + ) as unknown) as IAuthorizationConfig; + + exampleConfig.configFile = ""; + + const convictConfig = configService.newExampleConfigConvict(exampleConfig); + t.ok(convictConfig, "configService.newExampleConfigConvict() truthy OK"); + + const config = convictConfig.getProperties(); + t.ok(config, "convictConfig.getProperties() truthy OK"); + + LoggerProvider.setLogLevel(config.logLevel); + const apiServer = new ApiServer({ config }); + await apiServer.start(); + test.onFinish(() => apiServer.shutdown()); + t.end(); +});