diff --git a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/README.md b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/README.md index 5a8b0a21b67..43a274e5615 100644 --- a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/README.md +++ b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/README.md @@ -15,7 +15,6 @@ Install the following dependencies: ```shell go get github.com/stretchr/testify/assert -go get golang.org/x/oauth2 go get golang.org/x/net/context ``` @@ -94,33 +93,14 @@ Class | Method | HTTP request | Description Authentication schemes defined for the API: -### OAuth2 +### bearerTokenAuth - -- **Type**: OAuth -- **Flow**: accessCode -- **Authorization URL**: http://0.0.0.0:4000/oauth/authorize -- **Scopes**: - - **read:health**: Read health information - - **read:metrics**: Read metrics information - - **read:spec**: Read OpenAPI specification +- **Type**: HTTP Bearer token authentication Example ```golang -auth := context.WithValue(context.Background(), sw.ContextAccessToken, "ACCESSTOKENSTRING") -r, err := client.Service.Operation(auth, args) -``` - -Or via OAuth2 module to automatically refresh tokens and perform user authentication. - -```golang -import "golang.org/x/oauth2" - -/* Perform OAuth2 round trip request and obtain a token */ - -tokenSource := oauth2cfg.TokenSource(createContext(httpClient), &token) -auth := context.WithValue(oauth2.NoContext, sw.ContextOAuth2, tokenSource) +auth := context.WithValue(context.Background(), sw.ContextAccessToken, "BEARER_TOKEN_STRING") r, err := client.Service.Operation(auth, args) ``` diff --git a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/api/openapi.yaml b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/api/openapi.yaml index f1aaf6f82be..576280acbac 100644 --- a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/api/openapi.yaml +++ b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/api/openapi.yaml @@ -9,7 +9,7 @@ info: servers: - url: / security: -- OAuth2: +- bearerTokenAuth: - read:health - read:metrics - read:spec @@ -29,7 +29,7 @@ paths: "401": description: Unauthorized security: - - OAuth2: + - bearerTokenAuth: - read:health summary: Can be used to verify liveness of an API server instance x-hyperledger-cacti: @@ -72,7 +72,7 @@ paths: "401": description: Unauthorized security: - - OAuth2: + - bearerTokenAuth: - read:spec x-hyperledger-cacti: http: @@ -148,13 +148,7 @@ components: nullable: false type: string securitySchemes: - OAuth2: - flows: - authorizationCode: - authorizationUrl: http://0.0.0.0:4000/oauth/authorize - scopes: - read:health: Read health information - read:metrics: Read metrics information - read:spec: Read OpenAPI specification - tokenUrl: http://0.0.0.0:4000/oauth/token - type: oauth2 + bearerTokenAuth: + bearerFormat: JSON Web Tokens + scheme: bearer + type: http diff --git a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/client.go b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/client.go index 1c580a49fc1..758e67f1384 100644 --- a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/client.go +++ b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/client.go @@ -32,7 +32,6 @@ import ( "time" "unicode/utf8" - "golang.org/x/oauth2" ) var ( @@ -411,15 +410,9 @@ func (c *APIClient) prepareRequest( // Walk through any authentication. - // OAuth2 authentication - if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok { - // We were able to grab an oauth2 token from the context - var latestToken *oauth2.Token - if latestToken, err = tok.Token(); err != nil { - return nil, err - } - - latestToken.SetAuthHeader(localVarRequest) + // AccessToken Authentication + if auth, ok := ctx.Value(ContextAccessToken).(string); ok { + localVarRequest.Header.Add("Authorization", "Bearer "+auth) } } diff --git a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/configuration.go b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/configuration.go index 93fab77d64b..91b1c589ce4 100644 --- a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/configuration.go +++ b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/configuration.go @@ -28,8 +28,8 @@ func (c contextKey) String() string { } var ( - // ContextOAuth2 takes an oauth2.TokenSource as authentication for the request. - ContextOAuth2 = contextKey("token") + // ContextAccessToken takes a string oauth2 access token as authentication for the request. + ContextAccessToken = contextKey("accesstoken") // ContextServerIndex uses a server configuration from the index. ContextServerIndex = contextKey("serverIndex") diff --git a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/go.mod b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/go.mod index 18881d23d4a..cf6f7e9b4ab 100644 --- a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/go.mod +++ b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/go.mod @@ -3,5 +3,4 @@ module github.com/hyperledger/cactus-cmd-api-server/src/main/go/generated/openap go 1.18 require ( - golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 ) diff --git a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/go.sum b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/go.sum index 734252e6815..c966c8ddfd0 100644 --- a/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/go.sum +++ b/packages/cactus-cmd-api-server/src/main/go/generated/openapi/go-client/go.sum @@ -4,8 +4,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/packages/cactus-cmd-api-server/src/main/json/openapi.json b/packages/cactus-cmd-api-server/src/main/json/openapi.json index 4be9e9b9aa7..cda0f7eb923 100644 --- a/packages/cactus-cmd-api-server/src/main/json/openapi.json +++ b/packages/cactus-cmd-api-server/src/main/json/openapi.json @@ -78,25 +78,16 @@ } }, "securitySchemes": { - "OAuth2": { - "type": "oauth2", - "flows": { - "authorizationCode": { - "authorizationUrl": "https://example.com/oauth/authorize", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "read:health": "Read health information", - "read:metrics": "Read metrics information", - "read:spec": "Read OpenAPI specification" - } - } - } + "bearerTokenAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JSON Web Tokens" } } }, "security": [ { - "OAuth2": ["read:health", "read:metrics", "read:spec"] + "bearerTokenAuth": ["read:health", "read:metrics", "read:spec"] } ], "paths": { @@ -129,7 +120,7 @@ }, "security": [ { - "OAuth2": ["read:health"] + "bearerTokenAuth": ["read:health"] } ] } @@ -195,7 +186,7 @@ }, "security": [ { - "OAuth2": ["read:spec"] + "bearerTokenAuth": ["read:spec"] } ] } diff --git a/packages/cactus-cmd-api-server/src/main/json/openapi.tpl.json b/packages/cactus-cmd-api-server/src/main/json/openapi.tpl.json index 4be9e9b9aa7..cda0f7eb923 100644 --- a/packages/cactus-cmd-api-server/src/main/json/openapi.tpl.json +++ b/packages/cactus-cmd-api-server/src/main/json/openapi.tpl.json @@ -78,25 +78,16 @@ } }, "securitySchemes": { - "OAuth2": { - "type": "oauth2", - "flows": { - "authorizationCode": { - "authorizationUrl": "https://example.com/oauth/authorize", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "read:health": "Read health information", - "read:metrics": "Read metrics information", - "read:spec": "Read OpenAPI specification" - } - } - } + "bearerTokenAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JSON Web Tokens" } } }, "security": [ { - "OAuth2": ["read:health", "read:metrics", "read:spec"] + "bearerTokenAuth": ["read:health", "read:metrics", "read:spec"] } ], "paths": { @@ -129,7 +120,7 @@ }, "security": [ { - "OAuth2": ["read:health"] + "bearerTokenAuth": ["read:health"] } ] } @@ -195,7 +186,7 @@ }, "security": [ { - "OAuth2": ["read:spec"] + "bearerTokenAuth": ["read:spec"] } ] } diff --git a/packages/cactus-cmd-api-server/src/main/kotlin/generated/openapi/kotlin-client/README.md b/packages/cactus-cmd-api-server/src/main/kotlin/generated/openapi/kotlin-client/README.md index 240e5bb723f..284fb09568b 100644 --- a/packages/cactus-cmd-api-server/src/main/kotlin/generated/openapi/kotlin-client/README.md +++ b/packages/cactus-cmd-api-server/src/main/kotlin/generated/openapi/kotlin-client/README.md @@ -62,14 +62,8 @@ Class | Method | HTTP request | Description Authentication schemes defined for the API: - -### OAuth2 - -- **Type**: OAuth -- **Flow**: accessCode -- **Authorization URL**: http://0.0.0.0:4000/oauth/authorize -- **Scopes**: - - read:health: Read health information - - read:metrics: Read metrics information - - read:spec: Read OpenAPI specification + +### bearerTokenAuth + +- **Type**: HTTP basic authentication diff --git a/packages/cactus-cmd-api-server/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/packages/cactus-cmd-api-server/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt index 79a51064818..c83d4d4d575 100644 --- a/packages/cactus-cmd-api-server/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt +++ b/packages/cactus-cmd-api-server/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt @@ -146,7 +146,7 @@ open class ApiClient(val baseUrl: String, val client: OkHttpClient = defaultClie protected fun updateAuthParams(requestConfig: RequestConfig) { if (requestConfig.headers[Authorization].isNullOrEmpty()) { accessToken?.let { accessToken -> - requestConfig.headers[Authorization] = "Bearer $accessToken " + requestConfig.headers[Authorization] = "Bearer $accessToken" } } } diff --git a/packages/cactus-cmd-api-server/src/main/typescript/api-server.ts b/packages/cactus-cmd-api-server/src/main/typescript/api-server.ts index c49ad51ba91..1e1333ea90d 100644 --- a/packages/cactus-cmd-api-server/src/main/typescript/api-server.ts +++ b/packages/cactus-cmd-api-server/src/main/typescript/api-server.ts @@ -81,6 +81,10 @@ import { GetOpenApiSpecV1Endpoint, IGetOpenApiSpecV1EndpointOptions, } from "./web-services/get-open-api-spec-v1-endpoint"; +import { + GetHealthcheckV1Endpoint, + IGetHealthcheckV1EndpointOptions, +} from "./web-services/get-healthcheck-v1-endpoint"; export interface IApiServerConstructorOptions { readonly pluginManagerOptions?: { pluginsPath: string }; @@ -640,6 +644,15 @@ export class ApiServer { const { logLevel } = this.options.config; const pluginRegistry = await this.getOrInitPluginRegistry(); + { + const opts: IGetHealthcheckV1EndpointOptions = { + process: global.process, + logLevel, + }; + const endpoint = new GetHealthcheckV1Endpoint(opts); + await registerWebServiceEndpoint(app, endpoint); + } + { const oasPath = OAS.paths["/api/v1/api-server/get-open-api-spec"]; @@ -657,23 +670,6 @@ export class ApiServer { await registerWebServiceEndpoint(app, endpoint); } - const healthcheckHandler = (req: Request, res: Response) => { - res.json({ - success: true, - createdAt: new Date(), - memoryUsage: process.memoryUsage(), - }); - }; - - const { "/api/v1/api-server/healthcheck": oasPath } = OAS.paths; - const { http } = oasPath.get["x-hyperledger-cacti"]; - const { path: httpPath, verbLowerCase: httpVerb } = http; - if (!isExpressHttpVerbMethodName(httpVerb)) { - const eMsg = `${fnTag} Invalid HTTP verb "${httpVerb}" in cmd-api-server OpenAPI specification for HTTP path: "${httpPath}"`; - throw new RuntimeError(eMsg); - } - app[httpVerb](httpPath, healthcheckHandler); - this.wsApi.on("connection", (socket: SocketIoSocket) => { const { id } = socket; const transport = socket.conn.transport.name; // in most cases, "polling" diff --git a/packages/cactus-cmd-api-server/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-cmd-api-server/src/main/typescript/generated/openapi/typescript-axios/api.ts index 8af7d7dc2c7..9531721455f 100644 --- a/packages/cactus-cmd-api-server/src/main/typescript/generated/openapi/typescript-axios/api.ts +++ b/packages/cactus-cmd-api-server/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -128,9 +128,9 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; - // authentication OAuth2 required - // oauth required - await setOAuthToObject(localVarHeaderParameter, "OAuth2", ["read:health"], configuration) + // authentication bearerTokenAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) @@ -161,9 +161,9 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; - // authentication OAuth2 required - // oauth required - await setOAuthToObject(localVarHeaderParameter, "OAuth2", ["read:spec"], configuration) + // authentication bearerTokenAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) @@ -195,9 +195,9 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; - // authentication OAuth2 required - // oauth required - await setOAuthToObject(localVarHeaderParameter, "OAuth2", ["read:metrics"], configuration) + // authentication bearerTokenAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) diff --git a/packages/cactus-cmd-api-server/src/main/typescript/web-services/get-healthcheck-v1-endpoint.ts b/packages/cactus-cmd-api-server/src/main/typescript/web-services/get-healthcheck-v1-endpoint.ts new file mode 100644 index 00000000000..f1ee542cdaf --- /dev/null +++ b/packages/cactus-cmd-api-server/src/main/typescript/web-services/get-healthcheck-v1-endpoint.ts @@ -0,0 +1,117 @@ +import { StatusCodes } from "http-status-codes"; +import type { Express, Request, Response } from "express"; + +import { + Checks, + IAsyncProvider, + Logger, + LoggerProvider, + LogLevelDesc, +} from "@hyperledger/cactus-common"; +import { + IEndpointAuthzOptions, + IExpressRequestHandler, + IWebServiceEndpoint, +} from "@hyperledger/cactus-core-api"; +import { + handleRestEndpointException, + IHandleRestEndpointExceptionOptions, + registerWebServiceEndpoint, +} from "@hyperledger/cactus-core"; + +import OAS from "../../json/openapi.json"; + +export interface IGetHealthcheckV1EndpointOptions { + readonly logLevel?: LogLevelDesc; + readonly process: NodeJS.Process; +} + +export class GetHealthcheckV1Endpoint implements IWebServiceEndpoint { + public static readonly CLASS_NAME = "GetHealthcheckV1Endpoint"; + + private readonly log: Logger; + + private readonly process: NodeJS.Process; + + public get className(): string { + return GetHealthcheckV1Endpoint.CLASS_NAME; + } + + constructor(public readonly opts: IGetHealthcheckV1EndpointOptions) { + const fnTag = `${this.className}#constructor()`; + Checks.truthy(opts, `${fnTag} arg opts`); + Checks.truthy(opts.process, `${fnTag} arg opts.process`); + + this.process = opts.process; + + const level = this.opts.logLevel || "INFO"; + const label = this.className; + this.log = LoggerProvider.getOrCreate({ level, label }); + } + + public getAuthorizationOptionsProvider(): IAsyncProvider { + return { + get: async () => ({ + isProtected: true, + requiredRoles: this.oasPath.get.security[0].bearerTokenAuth, + }), + }; + } + + public getExpressRequestHandler(): IExpressRequestHandler { + return this.handleRequest.bind(this); + } + + public get oasPath(): (typeof OAS.paths)["/api/v1/api-server/healthcheck"] { + return OAS.paths["/api/v1/api-server/healthcheck"]; + } + + public getPath(): string { + return this.oasPath.get["x-hyperledger-cacti"].http.path; + } + + public getVerbLowerCase(): string { + return this.oasPath.get["x-hyperledger-cacti"].http.verbLowerCase; + } + + public getOperationId(): string { + return this.oasPath.get.operationId; + } + + public async registerExpress( + expressApp: Express, + ): Promise { + await registerWebServiceEndpoint(expressApp, this); + return this; + } + + async handleRequest(_req: Request, res: Response): Promise { + const fnTag = `${this.className}#handleRequest()`; + const verbUpper = this.getVerbLowerCase().toUpperCase(); + const reqTag = `${verbUpper} ${this.getPath()}`; + this.log.debug(reqTag); + + try { + const memoryUsage = this.process.memoryUsage(); + const createdAt = new Date(); + const body = { + success: true, + createdAt, + memoryUsage, + }; + res.json(body).status(StatusCodes.OK); + } catch (error) { + const { log } = this; + const errorMsg = `${fnTag} request handler fn crashed for: ${reqTag}`; + + const ctx: Readonly = { + errorMsg, + log, + error, + res, + }; + + await handleRestEndpointException(ctx); + } + } +} diff --git a/packages/cactus-cmd-api-server/src/main/typescript/web-services/get-open-api-spec-v1-endpoint.ts b/packages/cactus-cmd-api-server/src/main/typescript/web-services/get-open-api-spec-v1-endpoint.ts index 79b3e6d4b0c..c71993819b0 100644 --- a/packages/cactus-cmd-api-server/src/main/typescript/web-services/get-open-api-spec-v1-endpoint.ts +++ b/packages/cactus-cmd-api-server/src/main/typescript/web-services/get-open-api-spec-v1-endpoint.ts @@ -3,8 +3,15 @@ import { IGetOpenApiSpecV1EndpointBaseOptions, } from "@hyperledger/cactus-core"; -import { Checks, LogLevelDesc } from "@hyperledger/cactus-common"; -import { IWebServiceEndpoint } from "@hyperledger/cactus-core-api"; +import { + Checks, + IAsyncProvider, + LogLevelDesc, +} from "@hyperledger/cactus-common"; +import { + IEndpointAuthzOptions, + IWebServiceEndpoint, +} from "@hyperledger/cactus-core-api"; import OAS from "../../json/openapi.json"; @@ -34,4 +41,13 @@ export class GetOpenApiSpecV1Endpoint const fnTag = `${this.className}#constructor()`; Checks.truthy(options, `${fnTag} arg options`); } + + public getAuthorizationOptionsProvider(): IAsyncProvider { + return { + get: async () => ({ + isProtected: true, + requiredRoles: this.opts.oasPath.get.security[0].bearerTokenAuth, + }), + }; + } }