Skip to content

Commit c46e18d

Browse files
authored
Merge pull request #3780 from swagger-api/ft/oas3-authorization
OAS 3.0 Authorization
2 parents 353fd00 + 7c91732 commit c46e18d

File tree

16 files changed

+435
-56
lines changed

16 files changed

+435
-56
lines changed

dev-helpers/oauth2-redirect.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@
2727

2828
isValid = qp.state === sentState
2929

30-
if (oauth2.auth.schema.get("flow") === "accessCode" && !oauth2.auth.code) {
30+
if ((
31+
oauth2.auth.schema.get("flow") === "accessCode"||
32+
oauth2.auth.schema.get("flow") === "authorizationCode"
33+
) && !oauth2.auth.code) {
3134
if (!isValid) {
3235
oauth2.errCb({
3336
authId: oauth2.auth.name,

dist/oauth2-redirect.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@
2727

2828
isValid = qp.state === sentState
2929

30-
if (oauth2.auth.schema.get("flow") === "accessCode" && !oauth2.auth.code) {
30+
if ((
31+
oauth2.auth.schema.get("flow") === "accessCode"||
32+
oauth2.auth.schema.get("flow") === "authorizationCode"
33+
) && !oauth2.auth.code) {
3134
if (!isValid) {
3235
oauth2.errCb({
3336
authId: oauth2.auth.name,

src/core/components/auth/api-key-auth.jsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,15 @@ export default class ApiKeyAuth extends React.Component {
5151

5252
return (
5353
<div>
54-
<h4>Api key authorization<JumpToPath path={[ "securityDefinitions", name ]} /></h4>
54+
<h4>
55+
<code>{ name || schema.get("name") }</code>&nbsp;
56+
(apiKey)
57+
<JumpToPath path={[ "securityDefinitions", name ]} />
58+
</h4>
5559
{ value && <h6>Authorized</h6>}
5660
<Row>
5761
<Markdown source={ schema.get("description") } />
5862
</Row>
59-
<Row>
60-
<p>Name: <code>{ schema.get("name") }</code></p>
61-
</Row>
6263
<Row>
6364
<p>In: <code>{ schema.get("in") }</code></p>
6465
</Row>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React from "react"
2+
import PropTypes from "prop-types"
3+
import ImPropTypes from "react-immutable-proptypes"
4+
5+
export default class Auths extends React.Component {
6+
static propTypes = {
7+
schema: ImPropTypes.orderedMap.isRequired,
8+
name: PropTypes.string.isRequired,
9+
onAuthChange: PropTypes.func.isRequired,
10+
authorized: ImPropTypes.orderedMap.isRequired
11+
}
12+
13+
render() {
14+
let {
15+
schema,
16+
name,
17+
getComponent,
18+
onAuthChange,
19+
authorized,
20+
errSelectors
21+
} = this.props
22+
const ApiKeyAuth = getComponent("apiKeyAuth")
23+
const BasicAuth = getComponent("basicAuth")
24+
25+
let authEl
26+
27+
const type = schema.get("type")
28+
29+
switch(type) {
30+
case "apiKey": authEl = <ApiKeyAuth key={ name }
31+
schema={ schema }
32+
name={ name }
33+
errSelectors={ errSelectors }
34+
authorized={ authorized }
35+
getComponent={ getComponent }
36+
onChange={ onAuthChange } />
37+
break
38+
case "basic": authEl = <BasicAuth key={ name }
39+
schema={ schema }
40+
name={ name }
41+
errSelectors={ errSelectors }
42+
authorized={ authorized }
43+
getComponent={ getComponent }
44+
onChange={ onAuthChange } />
45+
break
46+
default: authEl = <div key={ name }>Unknown security definition type { type }</div>
47+
}
48+
49+
return (<div key={`${name}-jump`}>
50+
{ authEl }
51+
</div>)
52+
}
53+
54+
static propTypes = {
55+
errSelectors: PropTypes.object.isRequired,
56+
getComponent: PropTypes.func.isRequired,
57+
authSelectors: PropTypes.object.isRequired,
58+
specSelectors: PropTypes.object.isRequired,
59+
authActions: PropTypes.object.isRequired,
60+
definitions: ImPropTypes.iterable.isRequired
61+
}
62+
}

src/core/components/auth/auths.jsx

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ export default class Auths extends React.Component {
2727
e.preventDefault()
2828

2929
let { authActions } = this.props
30-
3130
authActions.authorize(this.state)
3231
}
3332

@@ -44,8 +43,7 @@ export default class Auths extends React.Component {
4443

4544
render() {
4645
let { definitions, getComponent, authSelectors, errSelectors } = this.props
47-
const ApiKeyAuth = getComponent("apiKeyAuth")
48-
const BasicAuth = getComponent("basicAuth")
46+
const AuthItem = getComponent("AuthItem")
4947
const Oauth2 = getComponent("oauth2", true)
5048
const Button = getComponent("Button")
5149

@@ -64,33 +62,15 @@ export default class Auths extends React.Component {
6462
!!nonOauthDefinitions.size && <form onSubmit={ this.submitAuth }>
6563
{
6664
nonOauthDefinitions.map( (schema, name) => {
67-
let type = schema.get("type")
68-
let authEl
69-
70-
switch(type) {
71-
case "apiKey": authEl = <ApiKeyAuth key={ name }
72-
schema={ schema }
73-
name={ name }
74-
errSelectors={ errSelectors }
75-
authorized={ authorized }
76-
getComponent={ getComponent }
77-
onChange={ this.onAuthChange } />
78-
break
79-
case "basic": authEl = <BasicAuth key={ name }
80-
schema={ schema }
81-
name={ name }
82-
errSelectors={ errSelectors }
83-
authorized={ authorized }
84-
getComponent={ getComponent }
85-
onChange={ this.onAuthChange } />
86-
break
87-
default: authEl = <div key={ name }>Unknown security definition type { type }</div>
88-
}
89-
90-
return (<div key={`${name}-jump`}>
91-
{ authEl }
92-
</div>)
93-
65+
return <AuthItem
66+
key={name}
67+
schema={schema}
68+
name={name}
69+
getComponent={getComponent}
70+
onAuthChange={this.onAuthChange}
71+
authorized={authorized}
72+
errSelectors={errSelectors}
73+
/>
9474
}).toArray()
9575
}
9676
<div className="auth-btn-wrapper">

src/core/components/auth/oauth2.jsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@ import React from "react"
22
import PropTypes from "prop-types"
33
import oauth2Authorize from "core/oauth2-authorize"
44

5-
const IMPLICIT = "implicit"
6-
const ACCESS_CODE = "accessCode"
7-
const PASSWORD = "password"
8-
const APPLICATION = "application"
9-
105
export default class Oauth2 extends React.Component {
116
static propTypes = {
127
name: PropTypes.string,
@@ -16,6 +11,7 @@ export default class Oauth2 extends React.Component {
1611
authSelectors: PropTypes.object.isRequired,
1712
authActions: PropTypes.object.isRequired,
1813
errSelectors: PropTypes.object.isRequired,
14+
specSelectors: PropTypes.object.isRequired,
1915
errActions: PropTypes.object.isRequired,
2016
getConfigs: PropTypes.any
2117
}
@@ -83,7 +79,9 @@ export default class Oauth2 extends React.Component {
8379
}
8480

8581
render() {
86-
let { schema, getComponent, authSelectors, errSelectors, name } = this.props
82+
let {
83+
schema, getComponent, authSelectors, errSelectors, name, specSelectors
84+
} = this.props
8785
const Input = getComponent("Input")
8886
const Row = getComponent("Row")
8987
const Col = getComponent("Col")
@@ -92,6 +90,14 @@ export default class Oauth2 extends React.Component {
9290
const JumpToPath = getComponent("JumpToPath", true)
9391
const Markdown = getComponent( "Markdown" )
9492

93+
const { isOAS3 } = specSelectors
94+
95+
// Auth type consts
96+
const IMPLICIT = "implicit"
97+
const PASSWORD = "password"
98+
const ACCESS_CODE = isOAS3() ? "authorizationCode" : "accessCode"
99+
const APPLICATION = isOAS3() ? "clientCredentials" : "application"
100+
95101
let flow = schema.get("flow")
96102
let scopes = schema.get("allowedScopes") || schema.get("scopes")
97103
let authorizedAuth = authSelectors.authorized().get(name)
@@ -102,7 +108,7 @@ export default class Oauth2 extends React.Component {
102108

103109
return (
104110
<div>
105-
<h4>OAuth2.0 <JumpToPath path={[ "securityDefinitions", name ]} /></h4>
111+
<h4>{name} (OAuth2, { schema.get("flow") }) <JumpToPath path={[ "securityDefinitions", name ]} /></h4>
106112
{ !this.state.appName ? null : <h5>Application: { this.state.appName } </h5> }
107113
{ description && <Markdown source={ schema.get("description") } /> }
108114

src/core/oauth2-authorize.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ export default function authorize ( { auth, authActions, errActions, configs, au
2222
case "implicit":
2323
query.push("response_type=token")
2424
break
25+
26+
case "clientCredentials":
27+
// OAS3
28+
authActions.authorizeApplication(auth)
29+
return
30+
31+
case "authorizationCode":
32+
// OAS3
33+
query.push("response_type=code")
34+
break
2535
}
2636

2737
if (typeof clientId === "string") {

src/core/plugins/auth/reducers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default {
2222
securities.entrySeq().forEach( ([ key, security ]) => {
2323
let type = security.getIn(["schema", "type"])
2424

25-
if ( type === "apiKey" ) {
25+
if ( type === "apiKey" || type === "http" ) {
2626
map = map.set(key, security)
2727
} else if ( type === "basic" ) {
2828
let username = security.getIn(["value", "username"])
Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,60 @@
11
import { createSelector } from "reselect"
2-
import { List } from "immutable"
2+
import { List, Map, fromJS } from "immutable"
33
import { isOAS3 as isOAS3Helper } from "../helpers"
44

55

66
// Helpers
77

8+
const state = state => state
9+
810
function onlyOAS3(selector) {
911
return (ori, system) => (state, ...args) => {
1012
const spec = system.getSystem().specSelectors.specJson()
1113
if(isOAS3Helper(spec)) {
12-
return selector(...args)
14+
return selector(system, ...args)
1315
} else {
1416
return ori(...args)
1517
}
1618
}
1719
}
1820

19-
const nullSelector = createSelector(() => null)
21+
export const definitionsToAuthorize = onlyOAS3(createSelector(
22+
state,
23+
({ specSelectors }) => {
24+
// Coerce our OpenAPI 3.0 definitions into monoflow definitions
25+
// that look like Swagger2 definitions.
26+
let definitions = specSelectors.securityDefinitions()
27+
let list = List()
28+
29+
definitions.entrySeq().forEach( ([ defName, definition ]) => {
30+
const type = definition.get("type")
2031

21-
const OAS3NullSelector = onlyOAS3(nullSelector)
32+
if(type === "oauth2") {
33+
definition.get("flows").entrySeq().forEach(([flowKey, flowVal]) => {
34+
let translatedDef = fromJS({
35+
flow: flowKey,
36+
authorizationUrl: flowVal.get("authorizationUrl"),
37+
tokenUrl: flowVal.get("tokenUrl"),
38+
scopes: flowVal.get("scopes"),
39+
type: definition.get("type")
40+
})
2241

23-
// Hasta la vista, authorization!
24-
export const shownDefinitions = OAS3NullSelector
25-
export const definitionsToAuthorize = OAS3NullSelector
26-
export const getDefinitionsByNames = OAS3NullSelector
27-
export const authorized = onlyOAS3(() => List())
28-
export const isAuthorized = OAS3NullSelector
29-
export const getConfigs = OAS3NullSelector
42+
list = list.push(new Map({
43+
[defName]: translatedDef.filter((v) => {
44+
// filter out unset values, sometimes `authorizationUrl`
45+
// and `tokenUrl` come out as `undefined` in the data
46+
return v !== undefined
47+
})
48+
}))
49+
})
50+
}
51+
if(type === "http" || type === "apiKey") {
52+
list = list.push(new Map({
53+
[defName]: definition
54+
}))
55+
}
56+
})
57+
58+
return list
59+
}
60+
))

0 commit comments

Comments
 (0)