From ae33b7f46a3fb89a7b702e7735db84c0754fb6ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20Mih=C3=A1ly?= Date: Wed, 5 Apr 2017 15:53:26 +0200 Subject: [PATCH] Implement application/client_credentials flow --- src/core/components/auth/oauth2.jsx | 6 +- src/core/components/auth/oauth2.jsx.orig | 218 +++++++++++++++++++++++ src/core/oauth2-authorize.js | 43 +++-- 3 files changed, 254 insertions(+), 13 deletions(-) create mode 100644 src/core/components/auth/oauth2.jsx.orig diff --git a/src/core/components/auth/oauth2.jsx b/src/core/components/auth/oauth2.jsx index 48fe946e..ec24eb01 100644 --- a/src/core/components/auth/oauth2.jsx +++ b/src/core/components/auth/oauth2.jsx @@ -145,7 +145,7 @@ export default class Oauth2 extends React.Component { } { - ( flow === IMPLICIT || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) && + ( flow === APPLICATION || flow === IMPLICIT || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) && ( !isAuthorized || isAuthorized && this.state.clientId) && @@ -159,7 +159,7 @@ export default class Oauth2 extends React.Component { } { - ( flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) && + ( flow === APPLICATION || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) && { @@ -205,7 +205,7 @@ export default class Oauth2 extends React.Component { } ) }
- { isValid && flow !== APPLICATION && + { isValid && ( isAuthorized ? : ) diff --git a/src/core/components/auth/oauth2.jsx.orig b/src/core/components/auth/oauth2.jsx.orig new file mode 100644 index 00000000..48fe946e --- /dev/null +++ b/src/core/components/auth/oauth2.jsx.orig @@ -0,0 +1,218 @@ +import React, { PropTypes } from "react" +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, + authorized: PropTypes.object, + getComponent: PropTypes.func.isRequired, + schema: PropTypes.object.isRequired, + authSelectors: PropTypes.object.isRequired, + authActions: PropTypes.object.isRequired, + errSelectors: PropTypes.object.isRequired, + errActions: PropTypes.object.isRequired, + getConfigs: PropTypes.any + } + + constructor(props, context) { + super(props, context) + let { name, schema, authorized } = this.props + let auth = authorized && authorized.get(name) + let username = auth && auth.get("username") || "" + let clientId = auth && auth.get("clientId") || "" + let clientSecret = auth && auth.get("clientSecret") || "" + let passwordType = auth && auth.get("passwordType") || "none" + + this.state = { + name: name, + schema: schema, + scopes: [], + clientId: clientId, + clientSecret: clientSecret, + username: username, + password: "", + passwordType: passwordType + } + } + + authorize =() => { + let { authActions, errActions, getConfigs } = this.props + let configs = getConfigs() + + errActions.clear({authId: name,type: "auth", source: "auth"}) + oauth2Authorize(this.state, authActions, errActions, configs) + } + + onScopeChange =(e) => { + let { target } = e + let { checked } = target + let scope = target.dataset.value + + if ( checked && this.state.scopes.indexOf(scope) === -1 ) { + let newScopes = this.state.scopes.concat([scope]) + this.setState({ scopes: newScopes }) + } else if ( !checked && this.state.scopes.indexOf(scope) > -1) { + this.setState({ scopes: this.state.scopes.filter((val) => val !== scope) }) + } + } + + onInputChange =(e) => { + let { target : { dataset : { name }, value } } = e + let state = { + [name]: value + } + + this.setState(state) + } + + logout =(e) => { + e.preventDefault() + let { authActions, errActions, name } = this.props + + errActions.clear({authId: name, type: "auth", source: "auth"}) + authActions.logout([ name ]) + } + + render() { + let { schema, getComponent, authSelectors, errSelectors, name } = this.props + const Input = getComponent("Input") + const Row = getComponent("Row") + const Col = getComponent("Col") + const Button = getComponent("Button") + const AuthError = getComponent("authError") + const JumpToPath = getComponent("JumpToPath", true) + const Markdown = getComponent( "Markdown" ) + + let flow = schema.get("flow") + let scopes = schema.get("allowedScopes") || schema.get("scopes") + let authorizedAuth = authSelectors.authorized().get(name) + let isAuthorized = !!authorizedAuth + let errors = errSelectors.allErrors().filter( err => err.get("authId") === name) + let isValid = !errors.filter( err => err.get("source") === "validation").size + + return ( +
+

OAuth2.0

+ + + { isAuthorized &&
Authorized
} + + { ( flow === IMPLICIT || flow === ACCESS_CODE ) &&

Authorization URL: { schema.get("authorizationUrl") }

} + { ( flow === PASSWORD || flow === ACCESS_CODE || flow === APPLICATION ) &&

Token URL: { schema.get("tokenUrl") }

} +

Flow: { schema.get("flow") }

+ + { + flow === PASSWORD && ( !isAuthorized || isAuthorized && this.state.username) && + username: + + { + isAuthorized ? { this.state.username } + : + } + + + } + + { + flow === PASSWORD && !isAuthorized && + password: + + + + + } + + { + flow === PASSWORD && + type: + + { + isAuthorized ? { this.state.passwordType } + : + } + + + } + + { + ( flow === IMPLICIT || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) && + ( !isAuthorized || isAuthorized && this.state.clientId) && + + + { + isAuthorized ? { this.state.clientId } + : + } + + + } + + { + ( flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) && + + + { + isAuthorized ? { this.state.clientSecret } + : + } + + + } + + { + !isAuthorized && scopes && scopes.size ?
+

Scopes:

+ { scopes.map((description, name) => { + return ( + +
+ + +
+
+ ) + }).toArray() + } +
: null + } + + { + errors.valueSeq().map( (error, key) => { + return + } ) + } +
+ { isValid && flow !== APPLICATION && + ( isAuthorized ? + : + ) + } +
+ +
+ ) + } +} diff --git a/src/core/oauth2-authorize.js b/src/core/oauth2-authorize.js index d02b8122..18f92985 100644 --- a/src/core/oauth2-authorize.js +++ b/src/core/oauth2-authorize.js @@ -1,7 +1,7 @@ import win from "core/window" export default function authorize ( auth, authActions, errActions, configs ) { - let { schema, scopes, name, clientId } = auth + let { schema, scopes, name, clientId, clientSecret } = auth let redirectUrl = configs.oauth2RedirectUrl let scopeSeparator = " " @@ -34,14 +34,37 @@ export default function authorize ( auth, authActions, errActions, configs ) { + "&state=" + encodeURIComponent(state) + "&client_id=" + encodeURIComponent(clientId) - // pass action authorizeOauth2 and authentication data through window - // to authorize with oauth2 - win.swaggerUIRedirectOauth2 = { - auth: auth, - state: state, - callback: authActions.preAuthorizeOauth2, - errCb: errActions.newAuthErr - } + console.log(flow); + if (flow === "application") { + fetch(schema.get("tokenUrl"), { + method: 'post', headers: { + 'Accept':'application/json, text/plain, */*', + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: "grant_type=client_credentials" + + "&client_id=" + encodeURIComponent(clientId) + + "&client_secret=" + encodeURIComponent(clientSecret) + + "&scope=" + encodeURIComponent(scopes.join(scopeSeparator)) + }) + .then(function (response) { + response.json() + .then(function (json){ + authActions.authorizeOauth2( { auth, token: json } ); + }); + }) + .catch (function (error) { + console.log('POST Request failed', error); + }); + } else { + // pass action authorizeOauth2 and authentication data through window + // to authorize with oauth2 + win.swaggerUIRedirectOauth2 = { + auth: auth, + state: state, + callback: authActions.preAuthorizeOauth2, + errCb: errActions.newAuthErr + } - win.open(url) + win.open(url) + } }