Skip to content

Commit

Permalink
Implement OAuth2 client authentication for password and application flow
Browse files Browse the repository at this point in the history
  • Loading branch information
MugeSo committed Nov 12, 2016
1 parent ddcb4b9 commit 297eb12
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 31 deletions.
57 changes: 29 additions & 28 deletions src/main/javascript/view/AuthView.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')) {
Expand Down Expand Up @@ -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);
Expand Down
14 changes: 12 additions & 2 deletions src/main/javascript/view/Oauth2Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},

Expand All @@ -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;
Expand Down
39 changes: 38 additions & 1 deletion src/main/javascript/view/Oauth2View.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
}
});
16 changes: 16 additions & 0 deletions src/main/template/oauth2.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@
<div><label>Password: <input class="oauth-password" type="password" name="password"></label></div>
</fieldset>
{{/if}}
{{#if clientAuthentication}}
<p>Setup client authentication.{{#if requireClientAuthenticaiton}}(Required){{/if}}</p>
<fieldset>
<div><label>Type:
<select class="oauth-client-authentication-type" name="client-authentication-type">
<option value="none" selected>None or other</option>
<option value="basic">Basic auth</option>
<option value="request-body">Request body</option>
</select>
</label></div>
<div class="oauth-client-authentication" hidden>
<div><label>ClientId: <input class="oauth-client-id" type="text" name="client-id"></label></div>
<div><label>Secret: <input class="oauth-client-secret" type="text" name="client-secret"></label></div>
</div>
</fieldset>
{{/if}}
<p><strong> {{{escape appName}}} </strong> API requires the following scopes. Select which ones you want to grant to Swagger UI.</p>
<p>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.
<a href="#">Learn how to use</a>
Expand Down

0 comments on commit 297eb12

Please sign in to comment.