feat: preauthorization (#4339)
* feat: swagger 2.0 preauthorization methods * tests: add cases for oas3 preauthorization * docs: add new preauth docs; touch up existing auth docs * tests: add `rootInject` tests * docs: remove unfinished sentence
This commit is contained in:
@@ -78,3 +78,9 @@ Parameter Name | Description
|
|||||||
--- | ---
|
--- | ---
|
||||||
`modelPropertyMacro` | `Function`. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
|
`modelPropertyMacro` | `Function`. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
|
||||||
`parameterMacro` | `Function`. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
|
`parameterMacro` | `Function`. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
|
||||||
|
|
||||||
|
### Instance methods
|
||||||
|
|
||||||
|
`initOAuth` | Provide Swagger-UI with information about your OAuth server - see the OAuth2 documentation for more information.
|
||||||
|
`preauthorizeBasic` | Programmatically set values for a Basic authorization scheme.
|
||||||
|
`preauthorizeApiKey` | Programmatically set values for an API key authorization scheme.
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# OAuth2 configuration
|
# OAuth2 configuration
|
||||||
You can configure OAuth2 authorization by calling `initOAuth` method with passed configs under the instance of `SwaggerUIBundle`
|
You can configure OAuth2 authorization by calling the `initOAuth` method.
|
||||||
default `client_id` and `client_secret`, `realm`, an application name `appName`, `scopeSeparator`, `additionalQueryStringParams`,
|
|
||||||
`useBasicAuthenticationWithAccessCodeGrant`.
|
|
||||||
|
|
||||||
Config Name | Description
|
Config Name | Description
|
||||||
--- | ---
|
--- | ---
|
||||||
@@ -11,7 +9,7 @@ realm | realm query parameter (for oauth1) added to `authorizationUrl` and `toke
|
|||||||
appName | application name, displayed in authorization popup. MUST be a string
|
appName | application name, displayed in authorization popup. MUST be a string
|
||||||
scopeSeparator | scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
|
scopeSeparator | scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
|
||||||
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
|
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
|
||||||
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 base64encoded[client_id:client_secret]`). The default is `false`
|
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`
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const ui = SwaggerUI({...})
|
const ui = SwaggerUI({...})
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export default function() {
|
|||||||
afterLoad(system) {
|
afterLoad(system) {
|
||||||
this.rootInjects = this.rootInjects || {}
|
this.rootInjects = this.rootInjects || {}
|
||||||
this.rootInjects.initOAuth = system.authActions.configureAuth
|
this.rootInjects.initOAuth = system.authActions.configureAuth
|
||||||
|
this.rootInjects.preauthorizeApiKey = preauthorizeApiKey.bind(null, system)
|
||||||
|
this.rootInjects.preauthorizeBasic = preauthorizeBasic.bind(null, system)
|
||||||
},
|
},
|
||||||
statePlugins: {
|
statePlugins: {
|
||||||
auth: {
|
auth: {
|
||||||
@@ -21,3 +23,50 @@ export default function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function preauthorizeBasic(system, key, username, password) {
|
||||||
|
const {
|
||||||
|
authActions: { authorize },
|
||||||
|
specSelectors: { specJson, isOAS3 }
|
||||||
|
} = system
|
||||||
|
|
||||||
|
const definitionBase = isOAS3() ? ["components", "securitySchemes"] : ["securityDefinitions"]
|
||||||
|
|
||||||
|
const schema = specJson().getIn([...definitionBase, key])
|
||||||
|
|
||||||
|
if(!schema) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return authorize({
|
||||||
|
[key]: {
|
||||||
|
value: {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
},
|
||||||
|
schema: schema.toJS()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function preauthorizeApiKey(system, key, value) {
|
||||||
|
const {
|
||||||
|
authActions: { authorize },
|
||||||
|
specSelectors: { specJson, isOAS3 }
|
||||||
|
} = system
|
||||||
|
|
||||||
|
const definitionBase = isOAS3() ? ["components", "securitySchemes"] : ["securityDefinitions"]
|
||||||
|
|
||||||
|
const schema = specJson().getIn([...definitionBase, key])
|
||||||
|
|
||||||
|
if(!schema) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return authorize({
|
||||||
|
[key]: {
|
||||||
|
value,
|
||||||
|
schema: schema.toJS()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
154
test/core/plugins/auth/preauthorize.js
Normal file
154
test/core/plugins/auth/preauthorize.js
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import expect from "expect"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import { preauthorizeBasic, preauthorizeApiKey } from "corePlugins/auth"
|
||||||
|
import { authorize } from "corePlugins/auth/actions"
|
||||||
|
|
||||||
|
const S2_SYSTEM = {
|
||||||
|
authActions: {
|
||||||
|
authorize
|
||||||
|
},
|
||||||
|
specSelectors: {
|
||||||
|
isOAS3: () => false,
|
||||||
|
specJson: () => {
|
||||||
|
return fromJS({
|
||||||
|
swagger: "2.0",
|
||||||
|
securityDefinitions: {
|
||||||
|
"APIKeyHeader": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"in": "header",
|
||||||
|
"name": "X-API-Key"
|
||||||
|
},
|
||||||
|
"basicAuth": {
|
||||||
|
"type": "basic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const OAI3_SYSTEM = {
|
||||||
|
authActions: {
|
||||||
|
authorize
|
||||||
|
},
|
||||||
|
specSelectors: {
|
||||||
|
isOAS3: () => true,
|
||||||
|
specJson: () => {
|
||||||
|
return fromJS({
|
||||||
|
openapi: "3.0.0",
|
||||||
|
components: {
|
||||||
|
securitySchemes: {
|
||||||
|
basicAuth: {
|
||||||
|
type: "http",
|
||||||
|
scheme: "basic"
|
||||||
|
},
|
||||||
|
APIKeyHeader: {
|
||||||
|
type: "apiKey",
|
||||||
|
in: "header",
|
||||||
|
name: "X-API-Key"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("auth plugin - preauthorizers", () => {
|
||||||
|
describe("preauthorizeBasic", () => {
|
||||||
|
it("should return a valid authorize action in Swagger 2", () => {
|
||||||
|
const res = preauthorizeBasic(S2_SYSTEM, "basicAuth", "user", "pass")
|
||||||
|
|
||||||
|
expect(res).toEqual({
|
||||||
|
type: "authorize",
|
||||||
|
payload: {
|
||||||
|
basicAuth: {
|
||||||
|
schema: {
|
||||||
|
type: "basic"
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
username: "user",
|
||||||
|
password: "pass"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
it("should return a valid authorize action in OpenAPI 3", () => {
|
||||||
|
const res = preauthorizeBasic(OAI3_SYSTEM, "basicAuth", "user", "pass")
|
||||||
|
|
||||||
|
expect(res).toEqual({
|
||||||
|
type: "authorize",
|
||||||
|
payload: {
|
||||||
|
basicAuth: {
|
||||||
|
schema: {
|
||||||
|
type: "http",
|
||||||
|
scheme: "basic"
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
username: "user",
|
||||||
|
password: "pass"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
it("should return null when the authorization name is invalid in Swagger 2", () => {
|
||||||
|
const res = preauthorizeBasic(S2_SYSTEM, "fakeBasicAuth", "user", "pass")
|
||||||
|
|
||||||
|
expect(res).toEqual(null)
|
||||||
|
})
|
||||||
|
it("should return null when the authorization name is invalid in OpenAPI 3", () => {
|
||||||
|
const res = preauthorizeBasic(OAI3_SYSTEM, "fakeBasicAuth", "user", "pass")
|
||||||
|
|
||||||
|
expect(res).toEqual(null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe("preauthorizeApiKey", () => {
|
||||||
|
it("should return a valid authorize action in Swagger 2", () => {
|
||||||
|
const res = preauthorizeApiKey(S2_SYSTEM, "APIKeyHeader", "Asdf1234")
|
||||||
|
|
||||||
|
expect(res).toEqual({
|
||||||
|
type: "authorize",
|
||||||
|
payload: {
|
||||||
|
APIKeyHeader: {
|
||||||
|
schema: {
|
||||||
|
type: "apiKey",
|
||||||
|
name: "X-API-Key",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
|
value: "Asdf1234"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
it("should return a valid authorize action in OpenAPI 3", () => {
|
||||||
|
const res = preauthorizeApiKey(OAI3_SYSTEM, "APIKeyHeader", "Asdf1234")
|
||||||
|
|
||||||
|
expect(res).toEqual({
|
||||||
|
type: "authorize",
|
||||||
|
payload: {
|
||||||
|
APIKeyHeader: {
|
||||||
|
schema: {
|
||||||
|
type: "apiKey",
|
||||||
|
"in": "header",
|
||||||
|
name: "X-API-Key"
|
||||||
|
},
|
||||||
|
value: "Asdf1234"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
it("should return null when the authorization name is invalid in Swagger 2", () => {
|
||||||
|
const res = preauthorizeApiKey(S2_SYSTEM, "FakeAPIKeyHeader", "Asdf1234")
|
||||||
|
|
||||||
|
expect(res).toEqual(null)
|
||||||
|
})
|
||||||
|
it("should return null when the authorization name is invalid in OpenAPI 3", () => {
|
||||||
|
const res = preauthorizeApiKey(OAI3_SYSTEM, "FakeAPIKeyHeader", "Asdf1234")
|
||||||
|
|
||||||
|
expect(res).toEqual(null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -701,6 +701,36 @@ describe("bound system", function(){
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("rootInjects", function() {
|
||||||
|
it("should attach a rootInject function as an instance method", function() {
|
||||||
|
// This is the same thing as the `afterLoad` tests, but is here for posterity
|
||||||
|
|
||||||
|
// Given
|
||||||
|
const system = new System({
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
afterLoad(system) {
|
||||||
|
this.rootInjects.wow = system.dogeSelectors.wow
|
||||||
|
},
|
||||||
|
statePlugins: {
|
||||||
|
doge: {
|
||||||
|
selectors: {
|
||||||
|
wow: () => (system) => {
|
||||||
|
return "so selective"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// When
|
||||||
|
var res = system.getSystem().wow()
|
||||||
|
expect(res).toEqual("so selective")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("error catching", function() {
|
describe("error catching", function() {
|
||||||
it("should encapsulate thrown errors in an afterLoad method", function() {
|
it("should encapsulate thrown errors in an afterLoad method", function() {
|
||||||
// Given
|
// Given
|
||||||
|
|||||||
Reference in New Issue
Block a user