From 297eb124979b66a008ea1c1e134d11b76a1812f0 Mon Sep 17 00:00:00 2001 From: TANAKA Koichi Date: Sat, 12 Nov 2016 23:17:10 +0900 Subject: [PATCH] Implement OAuth2 client authentication for password and application flow --- src/main/javascript/view/AuthView.js | 57 +++++++++++++------------ src/main/javascript/view/Oauth2Model.js | 14 +++++- src/main/javascript/view/Oauth2View.js | 39 ++++++++++++++++- src/main/template/oauth2.handlebars | 16 +++++++ 4 files changed, 95 insertions(+), 31 deletions(-) diff --git a/src/main/javascript/view/AuthView.js b/src/main/javascript/view/AuthView.js index 5c50df4cbde..3ca54d4b68c 100644 --- a/src/main/javascript/view/AuthView.js +++ b/src/main/javascript/view/AuthView.js @@ -116,13 +116,13 @@ SwaggerUi.Views.AuthView = Backbone.View.extend({ else if(auth.get('type') === 'oauth2' && flow && (flow === 'application')) { dets = auth.attributes; window.swaggerUi.tokenName = dets.tokenName || 'access_token'; - this.clientCredentialsFlow(scopes, dets.tokenUrl, window.OAuthSchemeKey); + this.clientCredentialsFlow(scopes, dets, window.OAuthSchemeKey); return; } else if(auth.get('type') === 'oauth2' && flow && (flow === 'password')) { dets = auth.attributes; window.swaggerUi.tokenName = dets.tokenName || 'access_token'; - this.passwordFlow(scopes, dets.tokenUrl, dets.username, dets.password, window.OAuthSchemeKey); + this.passwordFlow(scopes, dets, window.OAuthSchemeKey); return; } else if(auth.get('grantTypes')) { @@ -159,39 +159,40 @@ SwaggerUi.Views.AuthView = Backbone.View.extend({ }, // taken from lib/swagger-oauth.js - clientCredentialsFlow: function (scopes, tokenUrl, OAuthSchemeKey) { - var params = { - 'client_id': clientId, - 'client_secret': clientSecret, - 'scope': scopes.join(' '), - 'grant_type': 'client_credentials' - }; - $.ajax({ - url : tokenUrl, - type: 'POST', - data: params, - success: function (data) - { - onOAuthComplete(data, OAuthSchemeKey); - }, - error: function () - { - onOAuthComplete(''); - } + clientCredentialsFlow: function (scopes, oauth, OAuthSchemeKey) { + this.accessTokenRequest(scopes, oauth, OAuthSchemeKey, 'client_credentials'); + }, + + passwordFlow: function (scopes, oauth, OAuthSchemeKey) { + this.accessTokenRequest(scopes, oauth, OAuthSchemeKey, 'password', { + 'username': oauth.username, + 'password': oauth.password }); }, - passwordFlow: function (scopes, tokenUrl, username, password, OAuthSchemeKey) { - var params = { + accessTokenRequest: function (scopes, oauth, OAuthSchemeKey, grantType, params) { + params = $.extend({}, { 'scope': scopes.join(' '), - 'username': username, - 'password': password, - 'grant_type': 'password' - }; + 'grant_type': grantType + }, params); + + var headers= {}; + + switch (oauth.clientAuthenticationType) { + case 'basic': + headers.Authorization = 'Basic ' + btoa(oauth.clientId + ':' + oauth.clientSecret); + break; + case 'request-body': + params.client_id = oauth.clientId; + params.client_secret = oauth.clientSecret; + break; + } + $.ajax({ - url : tokenUrl, + url : oauth.tokenUrl, type: 'POST', data: params, + headers: headers, success: function (data) { onOAuthComplete(data, OAuthSchemeKey); diff --git a/src/main/javascript/view/Oauth2Model.js b/src/main/javascript/view/Oauth2Model.js index a7ceed420d8..645bf691d66 100644 --- a/src/main/javascript/view/Oauth2Model.js +++ b/src/main/javascript/view/Oauth2Model.js @@ -3,11 +3,16 @@ SwaggerUi.Models.Oauth2Model = Backbone.Model.extend({ defaults: { scopes: {}, - isPasswordFlow: false + isPasswordFlow: false, + clientAuthenticationType: 'none' }, initialize: function (attributes) { - this.set('isPasswordFlow', attributes.flow && attributes.flow === 'password'); + if (attributes.flow) { + this.set('isPasswordFlow', attributes.flow === 'password'); + this.set('requireClientAuthentication', attributes.flow === 'application'); + this.set('clientAuthentication', attributes.flow === 'password' || attributes.flow === 'application'); + } this.on('change', this.validate); }, @@ -29,6 +34,11 @@ SwaggerUi.Models.Oauth2Model = Backbone.Model.extend({ return false; } + if (this.get('clientAuthenticationType') in ['basic', 'request-body'] && + (!this.get('clientId'))) { + return false; + } + var scp = this.get('scopes'); var idx = _.findIndex(scp, function (o) { return o.checked === true; diff --git a/src/main/javascript/view/Oauth2View.js b/src/main/javascript/view/Oauth2View.js index 3bdd97fd8ea..63d56f23b6a 100644 --- a/src/main/javascript/view/Oauth2View.js +++ b/src/main/javascript/view/Oauth2View.js @@ -4,7 +4,10 @@ SwaggerUi.Views.Oauth2View = Backbone.View.extend({ events: { 'change .oauth-scope': 'scopeChange', 'change .oauth-username': 'setUsername', - 'change .oauth-password': 'setPassword' + 'change .oauth-password': 'setPassword', + 'change .oauth-client-authentication-type': 'setClientAuthenticationType', + 'change .oauth-client-id': 'setClientId', + 'change .oauth-client-secret': 'setClientSecret' }, template: Handlebars.templates.oauth2, @@ -38,9 +41,43 @@ SwaggerUi.Views.Oauth2View = Backbone.View.extend({ this.model.set('password', $(e.target).val()); }, + setClientAuthenticationType: function (e) { + var type = $(e.target).val(); + var $el = this.$el; + this.model.set('clientAuthenticationType', type); + + switch(type) { + case 'none': + $el.find('.oauth-client-authentication').hide(); + break; + case 'basic': + case 'request-body': + $el.find('.oauth-client-id').removeClass(this.cls.error); + $el.find('.oauth-client-authentication').show(); + break; + } + }, + + setClientId: function (e) { + var val = $(e.target).val(); + this.model.set('clientId', val); + if (val) { + $(e.target).removeClass(this.cls.error); + } + }, + + setClientSecret: function (e) { + this.model.set('clientSecret', $(e.target).val()); + $(e.target).removeClass('error'); + }, + highlightInvalid: function () { if (!this.model.get('username')) { this.$el.find('.oauth-username').addClass(this.cls.error); } + + if (!this.model.get('clientId')) { + this.$el.find('.oauth-client-id').addClass(this.cls.error); + } } }); \ No newline at end of file diff --git a/src/main/template/oauth2.handlebars b/src/main/template/oauth2.handlebars index 35db3a61352..3bd2a3612d1 100644 --- a/src/main/template/oauth2.handlebars +++ b/src/main/template/oauth2.handlebars @@ -11,6 +11,22 @@
{{/if}} + {{#if clientAuthentication}} +

Setup client authentication.{{#if requireClientAuthenticaiton}}(Required){{/if}}

+
+
+ +
+ {{/if}}

{{{escape appName}}} API requires the following scopes. Select which ones you want to grant to Swagger UI.

Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes. Learn how to use