Skip to content

Commit 3494d44

Browse files
committed
Implement OAuth2 client authentication for password and application flow
1 parent f2a1caa commit 3494d44

File tree

4 files changed

+97
-32
lines changed

4 files changed

+97
-32
lines changed

src/main/javascript/view/AuthView.js

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,13 @@ SwaggerUi.Views.AuthView = Backbone.View.extend({
119119
else if(auth.get('type') === 'oauth2' && flow && (flow === 'application')) {
120120
dets = auth.attributes;
121121
container.tokenName = dets.tokenName || 'access_token';
122-
this.clientCredentialsFlow(scopes, dets.tokenUrl, container.OAuthSchemeKey);
122+
this.clientCredentialsFlow(scopes, dets, container.OAuthSchemeKey);
123123
return;
124124
}
125125
else if(auth.get('type') === 'oauth2' && flow && (flow === 'password')) {
126126
dets = auth.attributes;
127-
window.swaggerUi.tokenName = dets.tokenName || 'access_token';
128-
this.passwordFlow(scopes, dets.tokenUrl, dets.username, dets.password, window.OAuthSchemeKey);
127+
container.tokenName = dets.tokenName || 'access_token';
128+
this.passwordFlow(scopes, dets, container.OAuthSchemeKey);
129129
return;
130130
}
131131
else if(auth.get('grantTypes')) {
@@ -162,39 +162,40 @@ SwaggerUi.Views.AuthView = Backbone.View.extend({
162162
},
163163

164164
// taken from lib/swagger-oauth.js
165-
clientCredentialsFlow: function (scopes, tokenUrl, OAuthSchemeKey) {
166-
var params = {
167-
'client_id': clientId,
168-
'client_secret': clientSecret,
169-
'scope': scopes.join(' '),
170-
'grant_type': 'client_credentials'
171-
};
172-
$.ajax({
173-
url : tokenUrl,
174-
type: 'POST',
175-
data: params,
176-
success: function (data)
177-
{
178-
onOAuthComplete(data, OAuthSchemeKey);
179-
},
180-
error: function ()
181-
{
182-
onOAuthComplete('');
183-
}
165+
clientCredentialsFlow: function (scopes, oauth, OAuthSchemeKey) {
166+
this.accessTokenRequest(scopes, oauth, OAuthSchemeKey, 'client_credentials');
167+
},
168+
169+
passwordFlow: function (scopes, oauth, OAuthSchemeKey) {
170+
this.accessTokenRequest(scopes, oauth, OAuthSchemeKey, 'password', {
171+
'username': oauth.username,
172+
'password': oauth.password
184173
});
185174
},
186175

187-
passwordFlow: function (scopes, tokenUrl, username, password, OAuthSchemeKey) {
188-
var params = {
176+
accessTokenRequest: function (scopes, oauth, OAuthSchemeKey, grantType, params) {
177+
params = $.extend({}, {
189178
'scope': scopes.join(' '),
190-
'username': username,
191-
'password': password,
192-
'grant_type': 'password'
193-
};
179+
'grant_type': grantType
180+
}, params);
181+
182+
var headers= {};
183+
184+
switch (oauth.clientAuthenticationType) {
185+
case 'basic':
186+
headers.Authorization = 'Basic ' + btoa(oauth.clientId + ':' + oauth.clientSecret);
187+
break;
188+
case 'request-body':
189+
params.client_id = oauth.clientId;
190+
params.client_secret = oauth.clientSecret;
191+
break;
192+
}
193+
194194
$.ajax({
195-
url : tokenUrl,
195+
url : oauth.tokenUrl,
196196
type: 'POST',
197197
data: params,
198+
headers: headers,
198199
success: function (data)
199200
{
200201
onOAuthComplete(data, OAuthSchemeKey);

src/main/javascript/view/Oauth2Model.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
SwaggerUi.Models.Oauth2Model = Backbone.Model.extend({
44
defaults: {
55
scopes: {},
6-
isPasswordFlow: false
6+
isPasswordFlow: false,
7+
clientAuthenticationType: 'none'
78
},
89

910
initialize: function () {
@@ -21,7 +22,12 @@ SwaggerUi.Models.Oauth2Model = Backbone.Model.extend({
2122
this.attributes = attributes;
2223
}
2324

24-
this.set('isPasswordFlow', attributes.flow && attributes.flow === 'password');
25+
if (this.attributes && this.attributes.flow) {
26+
var flow = this.attributes.flow;
27+
this.set('isPasswordFlow', flow === 'password');
28+
this.set('requireClientAuthentication', flow === 'application');
29+
this.set('clientAuthentication', flow === 'password' || flow === 'application');
30+
}
2531
this.on('change', this.validate);
2632
},
2733

@@ -43,6 +49,11 @@ SwaggerUi.Models.Oauth2Model = Backbone.Model.extend({
4349
return false;
4450
}
4551

52+
if (this.get('clientAuthenticationType') in ['basic', 'request-body'] &&
53+
(!this.get('clientId'))) {
54+
return false;
55+
}
56+
4657
var scp = this.get('scopes');
4758
var idx = _.findIndex(scp, function (o) {
4859
return o.checked === true;

src/main/javascript/view/Oauth2View.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ SwaggerUi.Views.Oauth2View = Backbone.View.extend({
44
events: {
55
'change .oauth-scope': 'scopeChange',
66
'change .oauth-username': 'setUsername',
7-
'change .oauth-password': 'setPassword'
7+
'change .oauth-password': 'setPassword',
8+
'change .oauth-client-authentication-type': 'setClientAuthenticationType',
9+
'change .oauth-client-id': 'setClientId',
10+
'change .oauth-client-secret': 'setClientSecret'
811
},
912

1013
template: Handlebars.templates.oauth2,
@@ -38,9 +41,43 @@ SwaggerUi.Views.Oauth2View = Backbone.View.extend({
3841
this.model.set('password', $(e.target).val());
3942
},
4043

44+
setClientAuthenticationType: function (e) {
45+
var type = $(e.target).val();
46+
var $el = this.$el;
47+
this.model.set('clientAuthenticationType', type);
48+
49+
switch(type) {
50+
case 'none':
51+
$el.find('.oauth-client-authentication').hide();
52+
break;
53+
case 'basic':
54+
case 'request-body':
55+
$el.find('.oauth-client-id').removeClass(this.cls.error);
56+
$el.find('.oauth-client-authentication').show();
57+
break;
58+
}
59+
},
60+
61+
setClientId: function (e) {
62+
var val = $(e.target).val();
63+
this.model.set('clientId', val);
64+
if (val) {
65+
$(e.target).removeClass(this.cls.error);
66+
}
67+
},
68+
69+
setClientSecret: function (e) {
70+
this.model.set('clientSecret', $(e.target).val());
71+
$(e.target).removeClass('error');
72+
},
73+
4174
highlightInvalid: function () {
4275
if (!this.model.get('username')) {
4376
this.$el.find('.oauth-username').addClass(this.cls.error);
4477
}
78+
79+
if (!this.model.get('clientId')) {
80+
this.$el.find('.oauth-client-id').addClass(this.cls.error);
81+
}
4582
}
4683
});

src/main/template/oauth2.handlebars

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,22 @@
1111
<div><label>Password: <input class="oauth-password" type="password" name="password"></label></div>
1212
</fieldset>
1313
{{/if}}
14+
{{#if clientAuthentication}}
15+
<p>Setup client authentication.{{#if requireClientAuthenticaiton}}(Required){{/if}}</p>
16+
<fieldset>
17+
<div><label>Type:
18+
<select class="oauth-client-authentication-type" name="client-authentication-type">
19+
<option value="none" selected>None or other</option>
20+
<option value="basic">Basic auth</option>
21+
<option value="request-body">Request body</option>
22+
</select>
23+
</label></div>
24+
<div class="oauth-client-authentication" hidden>
25+
<div><label>ClientId: <input class="oauth-client-id" type="text" name="client-id"></label></div>
26+
<div><label>Secret: <input class="oauth-client-secret" type="text" name="client-secret"></label></div>
27+
</div>
28+
</fieldset>
29+
{{/if}}
1430
<p><strong> {{{escape appName}}} </strong> API requires the following scopes. Select which ones you want to grant to Swagger UI.</p>
1531
<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.
1632
<a href="#">Learn how to use</a>

0 commit comments

Comments
 (0)