diff --git a/dev-helpers/oauth2-redirect.html b/dev-helpers/oauth2-redirect.html index a7eb162d..eb00dc68 100644 --- a/dev-helpers/oauth2-redirect.html +++ b/dev-helpers/oauth2-redirect.html @@ -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, diff --git a/dist/oauth2-redirect.html b/dist/oauth2-redirect.html index a7eb162d..eb00dc68 100644 --- a/dist/oauth2-redirect.html +++ b/dist/oauth2-redirect.html @@ -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, diff --git a/src/core/components/auth/oauth2.jsx b/src/core/components/auth/oauth2.jsx index 0632c259..2611779a 100644 --- a/src/core/components/auth/oauth2.jsx +++ b/src/core/components/auth/oauth2.jsx @@ -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, @@ -83,7 +78,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") @@ -92,6 +89,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) diff --git a/src/core/oauth2-authorize.js b/src/core/oauth2-authorize.js index fd3a4afc..c5521aaf 100644 --- a/src/core/oauth2-authorize.js +++ b/src/core/oauth2-authorize.js @@ -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") { diff --git a/src/core/plugins/auth/selectors.js b/src/core/plugins/auth/selectors.js index 5e84aebb..6e3b17b0 100644 --- a/src/core/plugins/auth/selectors.js +++ b/src/core/plugins/auth/selectors.js @@ -10,7 +10,7 @@ export const shownDefinitions = createSelector( export const definitionsToAuthorize = createSelector( state, - () =>( { specSelectors } ) => { + () => ( { specSelectors } ) => { let definitions = specSelectors.securityDefinitions() let list = List() @@ -27,7 +27,7 @@ export const definitionsToAuthorize = createSelector( ) -export const getDefinitionsByNames = ( state, securities ) =>( { specSelectors } ) => { +export const getDefinitionsByNames = ( state, securities ) => ( { specSelectors } ) => { let securityDefinitions = specSelectors.securityDefinitions() let result = List() @@ -64,7 +64,7 @@ export const authorized = createSelector( ) -export const isAuthorized = ( state, securities ) =>( { authSelectors } ) => { +export const isAuthorized = ( state, securities ) => ( { authSelectors } ) => { let authorized = authSelectors.authorized() if(!List.isList(securities)) { diff --git a/src/core/plugins/oas3/auth-extensions/wrap-selectors.js b/src/core/plugins/oas3/auth-extensions/wrap-selectors.js index 908c92e5..68f02ddd 100644 --- a/src/core/plugins/oas3/auth-extensions/wrap-selectors.js +++ b/src/core/plugins/oas3/auth-extensions/wrap-selectors.js @@ -1,29 +1,51 @@ 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) => (...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 ]) => { + 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") + }) -const OAS3NullSelector = onlyOAS3(nullSelector) + 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 + }) + })) + }) + }) -// Hasta la vista, authentication! -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 + return list + } +)) diff --git a/src/core/plugins/oas3/spec-extensions/wrap-selectors.js b/src/core/plugins/oas3/spec-extensions/wrap-selectors.js index ff892b4f..78ab05a8 100644 --- a/src/core/plugins/oas3/spec-extensions/wrap-selectors.js +++ b/src/core/plugins/oas3/spec-extensions/wrap-selectors.js @@ -48,12 +48,16 @@ export const definitions = onlyOAS3(createSelector( spec => spec.getIn(["components", "schemas"]) || Map() )) +export const securityDefinitions = onlyOAS3(createSelector( + spec, + spec => spec.getIn(["components", "securitySchemes"]) || Map() +)) + export const host = OAS3NullSelector export const basePath = OAS3NullSelector export const consumes = OAS3NullSelector export const produces = OAS3NullSelector export const schemes = OAS3NullSelector -export const securityDefinitions = OAS3NullSelector // New selectors diff --git a/test/core/plugins/oas3/wrap-auth-selectors.js b/test/core/plugins/oas3/wrap-auth-selectors.js new file mode 100644 index 00000000..1687d767 --- /dev/null +++ b/test/core/plugins/oas3/wrap-auth-selectors.js @@ -0,0 +1,116 @@ +/* eslint-env mocha */ +import expect, { createSpy } from "expect" +import { Map, fromJS } from "immutable" +import { + definitionsToAuthorize +} from "corePlugins/oas3/auth-extensions/wrap-selectors" + +describe.only("oas3 plugin - auth extensions - wrapSelectors", function(){ + + describe("execute", function(){ + + it("should add `securities` to the oriAction call", function(){ + // Given + const system = { + getSystem: () => system, + specSelectors: { + specJson: () => fromJS({ + openapi: "3.0.0" + }), + securityDefinitions: () => { + return fromJS({ + "oauth2AuthorizationCode": { + "type": "oauth2", + "flows": { + "authorizationCode": { + "authorizationUrl": "http://google.com/", + "tokenUrl": "http://google.com/", + "scopes": { + "myScope": "our only scope" + } + } + } + }, + "oauth2Multiflow": { + "type": "oauth2", + "flows": { + "clientCredentials": { + "tokenUrl": "http://google.com/", + "scopes": { + "myScope": "our only scope" + } + }, + "password": { + "tokenUrl": "http://google.com/", + "scopes": { + "myScope": "our only scope" + } + }, + "authorizationCode": { + "authorizationUrl": "http://google.com/", + "tokenUrl": "http://google.com/", + "scopes": { + "myScope": "our only scope" + } + } + } + } + }) + } + } + } + + // When + let res = definitionsToAuthorize(() => null, system)() + + // Then + expect(res.toJS()).toEqual([ + { + oauth2AuthorizationCode: { + flow: "authorizationCode", + authorizationUrl: "http://google.com/", + tokenUrl: "http://google.com/", + scopes: { + "myScope": "our only scope" + }, + type: "oauth2" + } + }, + { + oauth2Multiflow: { + flow: "clientCredentials", + tokenUrl: "http://google.com/", + scopes: { + "myScope": "our only scope" + }, + type: "oauth2" + } + }, + { + oauth2Multiflow: { + flow: "password", + tokenUrl: "http://google.com/", + scopes: { + "myScope": "our only scope" + }, + type: "oauth2" + } + }, + { + oauth2Multiflow: { + flow: "authorizationCode", + authorizationUrl: "http://google.com/", + tokenUrl: "http://google.com/", + scopes: { + "myScope": "our only scope" + }, + type: "oauth2" + } + }, + ]) + + }) + + }) + +})