diff --git a/src/main/javascript/view/AuthView.js b/src/main/javascript/view/AuthView.js index 5d692b84e1b..8511a994f81 100644 --- a/src/main/javascript/view/AuthView.js +++ b/src/main/javascript/view/AuthView.js @@ -119,7 +119,13 @@ SwaggerUi.Views.AuthView = Backbone.View.extend({ else if(auth.get('type') === 'oauth2' && flow && (flow === 'application')) { dets = auth.attributes; container.tokenName = dets.tokenName || 'access_token'; - this.clientCredentialsFlow(scopes, dets.tokenUrl, container.OAuthSchemeKey); + this.clientCredentialsFlow(scopes, dets, container.OAuthSchemeKey); + return; + } + else if(auth.get('type') === 'oauth2' && flow && (flow === 'password')) { + dets = auth.attributes; + container.tokenName = dets.tokenName || 'access_token'; + this.passwordFlow(scopes, dets, container.OAuthSchemeKey); return; } else if(auth.get('grantTypes')) { @@ -156,17 +162,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, + 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 + }); + }, + + accessTokenRequest: function (scopes, oauth, OAuthSchemeKey, grantType, params) { + params = $.extend({}, { 'scope': scopes.join(' '), - 'grant_type': 'client_credentials' - }; + '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); @@ -177,5 +206,4 @@ SwaggerUi.Views.AuthView = Backbone.View.extend({ } }); } - }); diff --git a/src/main/javascript/view/Oauth2Model.js b/src/main/javascript/view/Oauth2Model.js index a31b9528dce..7f9d7d2979d 100644 --- a/src/main/javascript/view/Oauth2Model.js +++ b/src/main/javascript/view/Oauth2Model.js @@ -2,7 +2,9 @@ SwaggerUi.Models.Oauth2Model = Backbone.Model.extend({ defaults: { - scopes: {} + scopes: {}, + isPasswordFlow: false, + clientAuthenticationType: 'none' }, initialize: function () { @@ -19,6 +21,13 @@ SwaggerUi.Models.Oauth2Model = Backbone.Model.extend({ attributes.scopes = scopes; this.attributes = attributes; } + + if (this.attributes && this.attributes.flow) { + var flow = this.attributes.flow; + this.set('isPasswordFlow', flow === 'password'); + this.set('requireClientAuthentication', flow === 'application'); + this.set('clientAuthentication', flow === 'password' || flow === 'application'); + } this.on('change', this.validate); }, @@ -35,6 +44,16 @@ SwaggerUi.Models.Oauth2Model = Backbone.Model.extend({ validate: function () { var valid = false; + if (this.get('isPasswordFlow') && + (!this.get('username'))) { + 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 6251511a12e..63d56f23b6a 100644 --- a/src/main/javascript/view/Oauth2View.js +++ b/src/main/javascript/view/Oauth2View.js @@ -2,11 +2,20 @@ SwaggerUi.Views.Oauth2View = Backbone.View.extend({ events: { - 'change .oauth-scope': 'scopeChange' + 'change .oauth-scope': 'scopeChange', + 'change .oauth-username': 'setUsername', + 'change .oauth-password': 'setPassword', + 'change .oauth-client-authentication-type': 'setClientAuthenticationType', + 'change .oauth-client-id': 'setClientId', + 'change .oauth-client-secret': 'setClientSecret' }, template: Handlebars.templates.oauth2, + cls: { + error: 'error' + }, + render: function () { this.$el.html(this.template(this.model.toJSON())); @@ -18,5 +27,57 @@ SwaggerUi.Views.Oauth2View = Backbone.View.extend({ var scope = $(e.target).data('scope'); this.model.setScopes(scope, val); + }, + + setUsername: function (e) { + var val= $(e.target).val(); + this.model.set('username', val); + if (val) { + $(e.target).removeClass(this.cls.error); + } + }, + + setPassword: function (e) { + 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/less/auth.less b/src/main/less/auth.less index 67c18faa457..c5d4338b5f3 100644 --- a/src/main/less/auth.less +++ b/src/main/less/auth.less @@ -201,4 +201,9 @@ } .api-popup-actions { padding-top: 10px; } + + fieldset { + padding-bottom: 10px; + padding-left: 20px; + } } diff --git a/src/main/template/oauth2.handlebars b/src/main/template/oauth2.handlebars index 44cf5111fea..3bd2a3612d1 100644 --- a/src/main/template/oauth2.handlebars +++ b/src/main/template/oauth2.handlebars @@ -1,12 +1,36 @@
-

Select OAuth2.0 Scopes

+

OAuth2.0

{{{sanitize description}}}

+ {{#if authorizationUrl}}

Authorization URL: {{{sanitize authorizationUrl}}}

{{/if}} + {{#if tokenUrl}}

Token URL: {{{sanitize tokenUrl}}}

{{/if}} +

flow: {{{escape flow}}}

+ {{#if isPasswordFlow}} +

Please input username and password for password flow authorization

+
+
+
+
+ {{/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

-

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

-

Authorization URL: {{{sanitize authorizationUrl}}}

-

flow: {{{escape flow}}}