Skip to content

Commit c6eb8ed

Browse files
authored
feature: Docker OAuth block support (via #4987)
* add `onFound` callback to schemas * add warning to method docs (for #4957) * implement Docker OAuth2 init block support * update docs * add OAUTH_SCOPE_SEPARATOR * drop OAuth env from Dockerfile and run script * don't indent the first oauth block line * drop unused `dedent` import * touch up warning message * add more test cases * return an empty block if no OAuth content is generated * fix broken doc line
1 parent 31a8b13 commit c6eb8ed

File tree

10 files changed

+286
-163
lines changed

10 files changed

+286
-163
lines changed

Dockerfile

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ RUN apk add nodejs
99
LABEL maintainer="fehguy"
1010

1111
ENV API_KEY "**None**"
12-
ENV OAUTH_CLIENT_ID "**None**"
13-
ENV OAUTH_CLIENT_SECRET "**None**"
14-
ENV OAUTH_REALM "**None**"
15-
ENV OAUTH_APP_NAME "**None**"
16-
ENV OAUTH_ADDITIONAL_PARAMS "**None**"
1712
ENV SWAGGER_JSON "/app/swagger.json"
1813
ENV PORT 8080
1914
ENV BASE_URL ""

docker/configurator/helpers.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module.exports.indent = function indent(str, len, fromLine = 0) {
2+
3+
return str
4+
.split("\n")
5+
.map((line, i) => {
6+
if (i + 1 >= fromLine) {
7+
return `${Array(len + 1).join(" ")}${line}`
8+
} else {
9+
return line
10+
}
11+
})
12+
.join("\n")
13+
}

docker/configurator/index.js

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ const fs = require("fs")
22
const path = require("path")
33

44
const translator = require("./translator")
5-
const configSchema = require("./variables")
5+
const oauthBlockBuilder = require("./oauth")
6+
const indent = require("./helpers").indent
67

78
const START_MARKER = "// Begin Swagger UI call region"
89
const END_MARKER = "// End Swagger UI call region"
@@ -22,19 +23,7 @@ fs.writeFileSync(targetPath, `${beforeStartMarkerContent}
2223
const ui = SwaggerUIBundle({
2324
${indent(translator(process.env, { injectBaseConfig: true }), 8, 2)}
2425
})
26+
27+
${indent(oauthBlockBuilder(process.env), 6, 2)}
2528
${END_MARKER}
26-
${afterEndMarkerContent}`)
27-
28-
function indent(str, len, fromLine) {
29-
30-
return str
31-
.split("\n")
32-
.map((line, i) => {
33-
if(i + 1 >= fromLine) {
34-
return `${Array(len + 1).join(" ")}${line}`
35-
} else {
36-
return line
37-
}
38-
})
39-
.join("\n")
40-
}
29+
${afterEndMarkerContent}`)

docker/configurator/oauth.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const translator = require("./translator")
2+
const indent = require("./helpers").indent
3+
4+
const oauthBlockSchema = {
5+
OAUTH_CLIENT_ID: {
6+
type: "string",
7+
name: "clientId"
8+
},
9+
OAUTH_CLIENT_SECRET: {
10+
type: "string",
11+
name: "clientSecret",
12+
onFound: () => console.warn("Swagger UI warning: don't use `OAUTH_CLIENT_SECRET` in production!")
13+
},
14+
OAUTH_REALM: {
15+
type: "string",
16+
name: "realm"
17+
},
18+
OAUTH_APP_NAME: {
19+
type: "string",
20+
name: "appName"
21+
},
22+
OAUTH_SCOPE_SEPARATOR: {
23+
type: "string",
24+
name: "scopeSeparator"
25+
},
26+
OAUTH_ADDITIONAL_PARAMS: {
27+
type: "object",
28+
name: "additionalQueryStringParams"
29+
}
30+
}
31+
32+
module.exports = function oauthBlockBuilder(env) {
33+
const translatorResult = translator(env, { schema: oauthBlockSchema })
34+
35+
if(translatorResult) {
36+
return (
37+
`ui.initOAuth({
38+
${indent(translatorResult, 2)}
39+
})`)
40+
}
41+
42+
return ``
43+
}

docker/configurator/translator.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ function objectToKeyValueString(env, { injectBaseConfig = false, schema = config
5555

5656
if(!varSchema) return
5757

58+
if(varSchema.onFound) {
59+
varSchema.onFound()
60+
}
61+
5862
const storageContents = valueStorage[varSchema.name]
5963

6064
if(storageContents) {

docker/run.sh

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,6 @@ if [ "${BASE_URL}" ]; then
2828
fi
2929

3030
replace_in_index myApiKeyXXXX123456789 $API_KEY
31-
replace_or_delete_in_index your-client-id $OAUTH_CLIENT_ID
32-
replace_or_delete_in_index your-client-secret-if-required $OAUTH_CLIENT_SECRET
33-
replace_or_delete_in_index your-realms $OAUTH_REALM
34-
replace_or_delete_in_index your-app-name $OAUTH_APP_NAME
35-
if [ "$OAUTH_ADDITIONAL_PARAMS" != "**None**" ]; then
36-
replace_in_index "additionalQueryStringParams: {}" "additionalQueryStringParams: {$OAUTH_ADDITIONAL_PARAMS}"
37-
fi
3831

3932
if [[ -f $SWAGGER_JSON ]]; then
4033
cp -s $SWAGGER_JSON $NGINX_ROOT

docs/usage/configuration.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,11 @@ Parameter name | Docker variable | Description
8181

8282
### Instance methods
8383

84-
Parameter name | Docker variable | Description
84+
**💡 Take note! These are methods, not parameters**.
85+
86+
Method name | Docker variable | Description
8587
--- | --- | -----
86-
<a name="initOAuth"></a>`initOAuth` | _Unavailable_ | `(configObj) => void`. Provide Swagger-UI with information about your OAuth server - see the OAuth2 documentation for more information.
88+
<a name="initOAuth"></a>`initOAuth` | [_See `oauth2.md`_](./oauth2.md) | `(configObj) => void`. Provide Swagger-UI with information about your OAuth server - see the OAuth2 documentation for more information.
8789
<a name="preauthorizeBasic"></a>`preauthorizeBasic` | _Unavailable_ | `(authDefinitionKey, username, password) => action`. Programmatically set values for a Basic authorization scheme.
8890
<a name="preauthorizeApiKey"></a>`preauthorizeApiKey` | _Unavailable_ | `(authDefinitionKey, apiKeyValue) => action`. Programmatically set values for an API key authorization scheme.
8991

docs/usage/oauth2.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# OAuth2 configuration
22
You can configure OAuth2 authorization by calling the `initOAuth` method.
33

4-
Config Name | Description
5-
--- | ---
6-
clientId | Default clientId. MUST be a string
7-
clientSecret | **🚨 Never use this parameter in your production environemnt. It exposes cruicial security information. This feature is intended for dev/test environments only. 🚨** <br>Default clientSecret. MUST be a string
8-
realm | realm query parameter (for oauth1) added to `authorizationUrl` and `tokenUrl`. MUST be a string
9-
appName | application name, displayed in authorization popup. MUST be a string
10-
scopeSeparator | scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
11-
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
12-
useBasicAuthenticationWithAccessCodeGrant | Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encode(client_id + client_secret)`). The default is `false`
4+
Property name | Docker variable | Description
5+
--- | --- | ------
6+
clientId | `OAUTH_CLIENT_ID` | Default clientId. MUST be a string
7+
clientSecret | `OAUTH_CLIENT_SECRET` | **🚨 Never use this parameter in your production environemnt. It exposes cruicial security information. This feature is intended for dev/test environments only. 🚨** <br>Default clientSecret. MUST be a string
8+
realm | `OAUTH_REALM` |realm query parameter (for oauth1) added to `authorizationUrl` and `tokenUrl`. MUST be a string
9+
appName | `OAUTH_APP_NAME` |application name, displayed in authorization popup. MUST be a string
10+
scopeSeparator | `OAUTH_SCOPE_SEPARATOR` |scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
11+
additionalQueryStringParams | `OAUTH_ADDITIONAL_PARAMS` |Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
12+
useBasicAuthenticationWithAccessCodeGrant | _Unavailable_ |Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encode(client_id + client_secret)`). The default is `false`
1313

1414
```javascript
1515
const ui = SwaggerUI({...})

test/docker/oauth.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
const expect = require("expect")
2+
const oauthBlockBuilder = require("../../docker/configurator/oauth")
3+
const dedent = require("dedent")
4+
5+
describe("docker: env translator - oauth block", function() {
6+
it("should omit the block if there are no valid keys", function () {
7+
const input = {}
8+
9+
expect(oauthBlockBuilder(input)).toEqual(``)
10+
})
11+
it("should omit the block if there are no valid keys", function () {
12+
const input = {
13+
NOT_A_VALID_KEY: "asdf1234"
14+
}
15+
16+
expect(oauthBlockBuilder(input)).toEqual(``)
17+
})
18+
it("should generate a block from empty values", function() {
19+
const input = {
20+
OAUTH_CLIENT_ID: ``,
21+
OAUTH_CLIENT_SECRET: ``,
22+
OAUTH_REALM: ``,
23+
OAUTH_APP_NAME: ``,
24+
OAUTH_SCOPE_SEPARATOR: "",
25+
OAUTH_ADDITIONAL_PARAMS: ``,
26+
}
27+
28+
expect(oauthBlockBuilder(input)).toEqual(dedent(`
29+
ui.initOAuth({
30+
clientId: "",
31+
clientSecret: "",
32+
realm: "",
33+
appName: "",
34+
scopeSeparator: "",
35+
additionalQueryStringParams: undefined,
36+
})`))
37+
})
38+
it("should generate a full block", function() {
39+
const input = {
40+
OAUTH_CLIENT_ID: `myId`,
41+
OAUTH_CLIENT_SECRET: `mySecret`,
42+
OAUTH_REALM: `myRealm`,
43+
OAUTH_APP_NAME: `myAppName`,
44+
OAUTH_SCOPE_SEPARATOR: "%21",
45+
OAUTH_ADDITIONAL_PARAMS: `{ "a": 1234, "b": "stuff" }`,
46+
}
47+
48+
expect(oauthBlockBuilder(input)).toEqual(dedent(`
49+
ui.initOAuth({
50+
clientId: "myId",
51+
clientSecret: "mySecret",
52+
realm: "myRealm",
53+
appName: "myAppName",
54+
scopeSeparator: "%21",
55+
additionalQueryStringParams: { "a": 1234, "b": "stuff" },
56+
})`))
57+
})
58+
})

0 commit comments

Comments
 (0)