Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client credential flow and multiple schemes #1825

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 66 additions & 27 deletions dist/lib/swagger-oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ var popupMask;
var popupDialog;
var clientId;
var realm;
var oauth2KeyName;
var redirect_uri;
var clientSecret;
var scopeSeparator;
Expand All @@ -19,7 +18,6 @@ function handleLogin() {
for(key in defs) {
var auth = defs[key];
if(auth.type === 'oauth2' && auth.scopes) {
oauth2KeyName = key;
var scope;
if(Array.isArray(auth.scopes)) {
// 1.2 support
Expand All @@ -31,7 +29,7 @@ function handleLogin() {
else {
// 2.0 support
for(scope in auth.scopes) {
scopes.push({scope: scope, description: auth.scopes[scope]});
scopes.push({scope: scope, description: auth.scopes[scope], OAuthSchemeKey: key});
}
}
}
Expand Down Expand Up @@ -61,12 +59,16 @@ function handleLogin() {
'</div>'].join(''));
$(document.body).append(popupDialog);

//TODO: only display applicable scopes (will need to pass them into handleLogin)
popup = popupDialog.find('ul.api-popup-scopes').empty();
for (i = 0; i < scopes.length; i ++) {
scope = scopes[i];
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"/>' + '<label for="scope_' + i + '">' + scope.scope;
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"' +'" oauthtype="' + scope.OAuthSchemeKey +'"/>' + '<label for="scope_' + i + '">' + scope.scope ;
if (scope.description) {
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>';
if ($.map(auths, function(n, i) { return i; }).length > 1) //if we have more than one scheme, display schemes
str += '<br/><span class="api-scope-desc">' + scope.description + ' ('+ scope.OAuthSchemeKey+')' +'</span>';
else
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>';
}
str += '</label></li>';
popup.append(str);
Expand Down Expand Up @@ -104,17 +106,40 @@ function handleLogin() {
var defaultRedirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html';
var redirectUrl = window.oAuthRedirectUrl || defaultRedirectUrl;
var url = null;

for (var key in authSchemes) {
if (authSchemes.hasOwnProperty(key)) {
var scopes = []
var o = popup.find('input:checked');
var OAuthSchemeKeys = [];
var state;
for(k =0; k < o.length; k++) {
var scope = $(o[k]).attr('scope');
if (scopes.indexOf(scope) === -1)
scopes.push(scope);
var OAuthSchemeKey = $(o[k]).attr('oauthtype');
if (OAuthSchemeKeys.indexOf(OAuthSchemeKey) === -1)
OAuthSchemeKeys.push(OAuthSchemeKey);
}

//TODO: merge not replace if scheme is different from any existing
//(needs to be aware of schemes to do so correctly)
window.enabledScopes=scopes;

for (var key in authSchemes) {
if (authSchemes.hasOwnProperty(key) && OAuthSchemeKeys.indexOf(key) != -1) { //only look at keys that match this scope.
var flow = authSchemes[key].flow;

if(authSchemes[key].type === 'oauth2' && flow && (flow === 'implicit' || flow === 'accessCode')) {
var dets = authSchemes[key];
url = dets.authorizationUrl + '?response_type=' + (flow === 'implicit' ? 'token' : 'code');
window.swaggerUi.tokenName = dets.tokenName || 'access_token';
window.swaggerUi.tokenUrl = (flow === 'accessCode' ? dets.tokenUrl : null);
state = key;
}
else if(authSchemes[key].type === 'oauth2' && flow && (flow === 'application')) {
var dets = authSchemes[key];
window.swaggerUi.tokenName = dets.tokenName || 'access_token';
clientCredentialsFlow(scopes, dets.tokenUrl, key);
return;
}
else if(authSchemes[key].grantTypes) {
// 1.2 support
var o = authSchemes[key].grantTypes;
Expand All @@ -135,20 +160,6 @@ function handleLogin() {
}
}
}
var scopes = []
var o = $('.api-popup-scopes').find('input:checked');

for(k =0; k < o.length; k++) {
var scope = $(o[k]).attr('scope');

if (scopes.indexOf(scope) === -1)
scopes.push(scope);
}

// Implicit auth recommends a state parameter.
var state = Math.random ();

window.enabledScopes=scopes;

redirect_uri = redirectUrl;

Expand Down Expand Up @@ -213,7 +224,32 @@ function initOAuth(opts) {
});
}

function clientCredentialsFlow(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, textStatus, jqXHR)
{
onOAuthComplete(data,OAuthSchemeKey);
},
error: function(jqXHR, textStatus, errorThrown)
{
onOAuthComplete("");
}
});

}

window.processOAuthCode = function processOAuthCode(data) {
var OAuthSchemeKey = data.state;
var params = {
'client_id': clientId,
'code': data.code,
Expand All @@ -232,7 +268,7 @@ window.processOAuthCode = function processOAuthCode(data) {
data: params,
success:function(data, textStatus, jqXHR)
{
onOAuthComplete(data);
onOAuthComplete(data, OAuthSchemeKey);
},
error: function(jqXHR, textStatus, errorThrown)
{
Expand All @@ -241,7 +277,7 @@ window.processOAuthCode = function processOAuthCode(data) {
});
};

window.onOAuthComplete = function onOAuthComplete(token) {
window.onOAuthComplete = function onOAuthComplete(token,OAuthSchemeKey) {
if(token) {
if(token.error) {
var checkbox = $('input[type=checkbox],.secured')
Expand All @@ -251,11 +287,14 @@ window.onOAuthComplete = function onOAuthComplete(token) {
alert(token.error);
}
else {
var b = token[window.swaggerUi.tokenName];
var b = token[window.swaggerUi.tokenName];
if (!OAuthSchemeKey){
OAuthSchemeKey = token.state;
}
if(b){
// if all roles are satisfied
var o = null;
$.each($('.auth .api-ic .api_information_panel'), function(k, v) {
$.each($('.auth .api-ic .api_information_panel'), function(k, v) {
var children = v;
if(children && children.childNodes) {
var requiredScopes = [];
Expand Down Expand Up @@ -292,7 +331,7 @@ window.onOAuthComplete = function onOAuthComplete(token) {
}
}
});
window.swaggerUi.api.clientAuthorizations.add(oauth2KeyName, new SwaggerClient.ApiKeyAuthorization('Authorization', 'Bearer ' + b, 'header'));
window.swaggerUi.api.clientAuthorizations.add(OAuthSchemeKey, new SwaggerClient.ApiKeyAuthorization('Authorization', 'Bearer ' + b, 'header'));
}
}
}
Expand Down
93 changes: 66 additions & 27 deletions lib/swagger-oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ var popupMask;
var popupDialog;
var clientId;
var realm;
var oauth2KeyName;
var redirect_uri;
var clientSecret;
var scopeSeparator;
Expand All @@ -19,7 +18,6 @@ function handleLogin() {
for(key in defs) {
var auth = defs[key];
if(auth.type === 'oauth2' && auth.scopes) {
oauth2KeyName = key;
var scope;
if(Array.isArray(auth.scopes)) {
// 1.2 support
Expand All @@ -31,7 +29,7 @@ function handleLogin() {
else {
// 2.0 support
for(scope in auth.scopes) {
scopes.push({scope: scope, description: auth.scopes[scope]});
scopes.push({scope: scope, description: auth.scopes[scope], OAuthSchemeKey: key});
}
}
}
Expand Down Expand Up @@ -61,12 +59,16 @@ function handleLogin() {
'</div>'].join(''));
$(document.body).append(popupDialog);

//TODO: only display applicable scopes (will need to pass them into handleLogin)
popup = popupDialog.find('ul.api-popup-scopes').empty();
for (i = 0; i < scopes.length; i ++) {
scope = scopes[i];
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"/>' + '<label for="scope_' + i + '">' + scope.scope;
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"' +'" oauthtype="' + scope.OAuthSchemeKey +'"/>' + '<label for="scope_' + i + '">' + scope.scope ;
if (scope.description) {
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>';
if ($.map(auths, function(n, i) { return i; }).length > 1) //if we have more than one scheme, display schemes
str += '<br/><span class="api-scope-desc">' + scope.description + ' ('+ scope.OAuthSchemeKey+')' +'</span>';
else
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>';
}
str += '</label></li>';
popup.append(str);
Expand Down Expand Up @@ -104,17 +106,40 @@ function handleLogin() {
var defaultRedirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html';
var redirectUrl = window.oAuthRedirectUrl || defaultRedirectUrl;
var url = null;

for (var key in authSchemes) {
if (authSchemes.hasOwnProperty(key)) {
var scopes = []
var o = popup.find('input:checked');
var OAuthSchemeKeys = [];
var state;
for(k =0; k < o.length; k++) {
var scope = $(o[k]).attr('scope');
if (scopes.indexOf(scope) === -1)
scopes.push(scope);
var OAuthSchemeKey = $(o[k]).attr('oauthtype');
if (OAuthSchemeKeys.indexOf(OAuthSchemeKey) === -1)
OAuthSchemeKeys.push(OAuthSchemeKey);
}

//TODO: merge not replace if scheme is different from any existing
//(needs to be aware of schemes to do so correctly)
window.enabledScopes=scopes;

for (var key in authSchemes) {
if (authSchemes.hasOwnProperty(key) && OAuthSchemeKeys.indexOf(key) != -1) { //only look at keys that match this scope.
var flow = authSchemes[key].flow;

if(authSchemes[key].type === 'oauth2' && flow && (flow === 'implicit' || flow === 'accessCode')) {
var dets = authSchemes[key];
url = dets.authorizationUrl + '?response_type=' + (flow === 'implicit' ? 'token' : 'code');
window.swaggerUi.tokenName = dets.tokenName || 'access_token';
window.swaggerUi.tokenUrl = (flow === 'accessCode' ? dets.tokenUrl : null);
state = key;
}
else if(authSchemes[key].type === 'oauth2' && flow && (flow === 'application')) {
var dets = authSchemes[key];
window.swaggerUi.tokenName = dets.tokenName || 'access_token';
clientCredentialsFlow(scopes, dets.tokenUrl, key);
return;
}
else if(authSchemes[key].grantTypes) {
// 1.2 support
var o = authSchemes[key].grantTypes;
Expand All @@ -135,20 +160,6 @@ function handleLogin() {
}
}
}
var scopes = []
var o = $('.api-popup-scopes').find('input:checked');

for(k =0; k < o.length; k++) {
var scope = $(o[k]).attr('scope');

if (scopes.indexOf(scope) === -1)
scopes.push(scope);
}

// Implicit auth recommends a state parameter.
var state = Math.random ();

window.enabledScopes=scopes;

redirect_uri = redirectUrl;

Expand Down Expand Up @@ -213,7 +224,32 @@ function initOAuth(opts) {
});
}

function clientCredentialsFlow(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, textStatus, jqXHR)
{
onOAuthComplete(data,OAuthSchemeKey);
},
error: function(jqXHR, textStatus, errorThrown)
{
onOAuthComplete("");
}
});

}

window.processOAuthCode = function processOAuthCode(data) {
var OAuthSchemeKey = data.state;
var params = {
'client_id': clientId,
'code': data.code,
Expand All @@ -232,7 +268,7 @@ window.processOAuthCode = function processOAuthCode(data) {
data: params,
success:function(data, textStatus, jqXHR)
{
onOAuthComplete(data);
onOAuthComplete(data, OAuthSchemeKey);
},
error: function(jqXHR, textStatus, errorThrown)
{
Expand All @@ -241,7 +277,7 @@ window.processOAuthCode = function processOAuthCode(data) {
});
};

window.onOAuthComplete = function onOAuthComplete(token) {
window.onOAuthComplete = function onOAuthComplete(token,OAuthSchemeKey) {
if(token) {
if(token.error) {
var checkbox = $('input[type=checkbox],.secured')
Expand All @@ -251,11 +287,14 @@ window.onOAuthComplete = function onOAuthComplete(token) {
alert(token.error);
}
else {
var b = token[window.swaggerUi.tokenName];
var b = token[window.swaggerUi.tokenName];
if (!OAuthSchemeKey){
OAuthSchemeKey = token.state;
}
if(b){
// if all roles are satisfied
var o = null;
$.each($('.auth .api-ic .api_information_panel'), function(k, v) {
$.each($('.auth .api-ic .api_information_panel'), function(k, v) {
var children = v;
if(children && children.childNodes) {
var requiredScopes = [];
Expand Down Expand Up @@ -292,7 +331,7 @@ window.onOAuthComplete = function onOAuthComplete(token) {
}
}
});
window.swaggerUi.api.clientAuthorizations.add(oauth2KeyName, new SwaggerClient.ApiKeyAuthorization('Authorization', 'Bearer ' + b, 'header'));
window.swaggerUi.api.clientAuthorizations.add(OAuthSchemeKey, new SwaggerClient.ApiKeyAuthorization('Authorization', 'Bearer ' + b, 'header'));
}
}
}
Expand Down