Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OAS 3.0 Authorization #3780

Merged
merged 5 commits into from
Oct 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion dev-helpers/oauth2-redirect.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@

isValid = qp.state === sentState

if (oauth2.auth.schema.get("flow") === "accessCode" && !oauth2.auth.code) {
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
Expand Down
5 changes: 4 additions & 1 deletion dist/oauth2-redirect.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@

isValid = qp.state === sentState

if (oauth2.auth.schema.get("flow") === "accessCode" && !oauth2.auth.code) {
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
Expand Down
9 changes: 5 additions & 4 deletions src/core/components/auth/api-key-auth.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,15 @@ export default class ApiKeyAuth extends React.Component {

return (
<div>
<h4>Api key authorization<JumpToPath path={[ "securityDefinitions", name ]} /></h4>
<h4>
<code>{ name || schema.get("name") }</code>&nbsp;
(apiKey)
<JumpToPath path={[ "securityDefinitions", name ]} />
</h4>
{ value && <h6>Authorized</h6>}
<Row>
<Markdown source={ schema.get("description") } />
</Row>
<Row>
<p>Name: <code>{ schema.get("name") }</code></p>
</Row>
<Row>
<p>In: <code>{ schema.get("in") }</code></p>
</Row>
Expand Down
62 changes: 62 additions & 0 deletions src/core/components/auth/auth-item.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"

export default class Auths extends React.Component {
static propTypes = {
schema: ImPropTypes.orderedMap.isRequired,
name: PropTypes.string.isRequired,
onAuthChange: PropTypes.func.isRequired,
authorized: ImPropTypes.orderedMap.isRequired
}

render() {
let {
schema,
name,
getComponent,
onAuthChange,
authorized,
errSelectors
} = this.props
const ApiKeyAuth = getComponent("apiKeyAuth")
const BasicAuth = getComponent("basicAuth")

let authEl

const type = schema.get("type")

switch(type) {
case "apiKey": authEl = <ApiKeyAuth key={ name }
schema={ schema }
name={ name }
errSelectors={ errSelectors }
authorized={ authorized }
getComponent={ getComponent }
onChange={ onAuthChange } />
break
case "basic": authEl = <BasicAuth key={ name }
schema={ schema }
name={ name }
errSelectors={ errSelectors }
authorized={ authorized }
getComponent={ getComponent }
onChange={ onAuthChange } />
break
default: authEl = <div key={ name }>Unknown security definition type { type }</div>
}

return (<div key={`${name}-jump`}>
{ authEl }
</div>)
}

static propTypes = {
errSelectors: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
authSelectors: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
definitions: ImPropTypes.iterable.isRequired
}
}
40 changes: 10 additions & 30 deletions src/core/components/auth/auths.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export default class Auths extends React.Component {
e.preventDefault()

let { authActions } = this.props

authActions.authorize(this.state)
}

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

render() {
let { definitions, getComponent, authSelectors, errSelectors } = this.props
const ApiKeyAuth = getComponent("apiKeyAuth")
const BasicAuth = getComponent("basicAuth")
const AuthItem = getComponent("AuthItem")
const Oauth2 = getComponent("oauth2", true)
const Button = getComponent("Button")

Expand All @@ -64,33 +62,15 @@ export default class Auths extends React.Component {
!!nonOauthDefinitions.size && <form onSubmit={ this.submitAuth }>
{
nonOauthDefinitions.map( (schema, name) => {
let type = schema.get("type")
let authEl

switch(type) {
case "apiKey": authEl = <ApiKeyAuth key={ name }
schema={ schema }
name={ name }
errSelectors={ errSelectors }
authorized={ authorized }
getComponent={ getComponent }
onChange={ this.onAuthChange } />
break
case "basic": authEl = <BasicAuth key={ name }
schema={ schema }
name={ name }
errSelectors={ errSelectors }
authorized={ authorized }
getComponent={ getComponent }
onChange={ this.onAuthChange } />
break
default: authEl = <div key={ name }>Unknown security definition type { type }</div>
}

return (<div key={`${name}-jump`}>
{ authEl }
</div>)

return <AuthItem
key={name}
schema={schema}
name={name}
getComponent={getComponent}
onAuthChange={this.onAuthChange}
authorized={authorized}
errSelectors={errSelectors}
/>
}).toArray()
}
<div className="auth-btn-wrapper">
Expand Down
20 changes: 13 additions & 7 deletions src/core/components/auth/oauth2.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ import React from "react"
import PropTypes from "prop-types"
import oauth2Authorize from "core/oauth2-authorize"

const IMPLICIT = "implicit"
const ACCESS_CODE = "accessCode"
const PASSWORD = "password"
const APPLICATION = "application"

export default class Oauth2 extends React.Component {
static propTypes = {
name: PropTypes.string,
Expand All @@ -16,6 +11,7 @@ export default class Oauth2 extends React.Component {
authSelectors: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
errSelectors: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
errActions: PropTypes.object.isRequired,
getConfigs: PropTypes.any
}
Expand Down Expand Up @@ -83,7 +79,9 @@ export default class Oauth2 extends React.Component {
}

render() {
let { schema, getComponent, authSelectors, errSelectors, name } = this.props
let {
schema, getComponent, authSelectors, errSelectors, name, specSelectors
} = this.props
const Input = getComponent("Input")
const Row = getComponent("Row")
const Col = getComponent("Col")
Expand All @@ -92,6 +90,14 @@ export default class Oauth2 extends React.Component {
const JumpToPath = getComponent("JumpToPath", true)
const Markdown = getComponent( "Markdown" )

const { isOAS3 } = specSelectors

// Auth type consts
const IMPLICIT = "implicit"
const PASSWORD = "password"
const ACCESS_CODE = isOAS3() ? "authorizationCode" : "accessCode"
const APPLICATION = isOAS3() ? "clientCredentials" : "application"

let flow = schema.get("flow")
let scopes = schema.get("allowedScopes") || schema.get("scopes")
let authorizedAuth = authSelectors.authorized().get(name)
Expand All @@ -102,7 +108,7 @@ export default class Oauth2 extends React.Component {

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

Expand Down
10 changes: 10 additions & 0 deletions src/core/oauth2-authorize.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ export default function authorize ( { auth, authActions, errActions, configs, au
case "implicit":
query.push("response_type=token")
break

case "clientCredentials":
// OAS3
authActions.authorizeApplication(auth)
return

case "authorizationCode":
// OAS3
query.push("response_type=code")
break
}

if (typeof clientId === "string") {
Expand Down
2 changes: 1 addition & 1 deletion src/core/plugins/auth/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default {
securities.entrySeq().forEach( ([ key, security ]) => {
let type = security.getIn(["schema", "type"])

if ( type === "apiKey" ) {
if ( type === "apiKey" || type === "http" ) {
map = map.set(key, security)
} else if ( type === "basic" ) {
let username = security.getIn(["value", "username"])
Expand Down
53 changes: 42 additions & 11 deletions src/core/plugins/oas3/auth-extensions/wrap-selectors.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,60 @@
import { createSelector } from "reselect"
import { List } from "immutable"
import { List, Map, fromJS } from "immutable"
import { isOAS3 as isOAS3Helper } from "../helpers"


// Helpers

const state = state => state

function onlyOAS3(selector) {
return (ori, system) => (state, ...args) => {
const spec = system.getSystem().specSelectors.specJson()
if(isOAS3Helper(spec)) {
return selector(...args)
return selector(system, ...args)
} else {
return ori(...args)
}
}
}

const nullSelector = createSelector(() => null)
export const definitionsToAuthorize = onlyOAS3(createSelector(
state,
({ specSelectors }) => {
// Coerce our OpenAPI 3.0 definitions into monoflow definitions
// that look like Swagger2 definitions.
let definitions = specSelectors.securityDefinitions()
let list = List()

definitions.entrySeq().forEach( ([ defName, definition ]) => {
const type = definition.get("type")

const OAS3NullSelector = onlyOAS3(nullSelector)
if(type === "oauth2") {
definition.get("flows").entrySeq().forEach(([flowKey, flowVal]) => {
let translatedDef = fromJS({
flow: flowKey,
authorizationUrl: flowVal.get("authorizationUrl"),
tokenUrl: flowVal.get("tokenUrl"),
scopes: flowVal.get("scopes"),
type: definition.get("type")
})

// Hasta la vista, authorization!
export const shownDefinitions = OAS3NullSelector
export const definitionsToAuthorize = OAS3NullSelector
export const getDefinitionsByNames = OAS3NullSelector
export const authorized = onlyOAS3(() => List())
export const isAuthorized = OAS3NullSelector
export const getConfigs = OAS3NullSelector
list = list.push(new Map({
[defName]: translatedDef.filter((v) => {
// filter out unset values, sometimes `authorizationUrl`
// and `tokenUrl` come out as `undefined` in the data
return v !== undefined
})
}))
})
}
if(type === "http" || type === "apiKey") {
list = list.push(new Map({
[defName]: definition
}))
}
})

return list
}
))
Loading