Added support for OAuth client credentials (application) flow

Added support for multiple authentication schemes

To use the client credentials, index.html needs to have
1. input boxes to recieve client id and client secret
2. handlers that intitialse OAuth correctly on change.

For example, you could replace the explore and apikey inputs in the header with:

      <div class='input'><input placeholder="client id" id="input_clientId" name="clientId" type="text" autocomplete="off"/></div>
      <div class='input'><input placeholder="client secret" id="input_clientSecret" name="clientSecret" type="text" autocomplete="off"/></div>

and add the following javascrip to handle updates within the initialisation block (replacing the apikey javascript):

      function updateOauth(){
          initOAuth({
              clientId: $('#input_clientId')[0].value,
              clientSecret: $('#input_clientSecret')[0].value,
              realm: "blank",
              appName: "blank"
          });
      }

      $('#input_clientId').change(updateOauth);
      $('#input_clientSecret').change(updateOauth);
This commit is contained in:
Tom Demeranville
2015-12-18 15:58:19 +00:00
parent 8e420faa23
commit b745779e15

View File

@@ -3,7 +3,6 @@ var popupMask;
var popupDialog;
var clientId;
var realm;
var oauth2KeyName;
var redirect_uri;
var clientSecret;
var scopeSeparator;
@@ -19,7 +18,7 @@ function handleLogin() {
for(key in defs) {
var auth = defs[key];
if(auth.type === 'oauth2' && auth.scopes) {
oauth2KeyName = key;
//oauth2KeyName = key;
var scope;
if(Array.isArray(auth.scopes)) {
// 1.2 support
@@ -31,7 +30,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});
}
}
}
@@ -61,12 +60,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 (auths.length > 1)
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);
@@ -104,9 +107,25 @@ 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')) {
@@ -114,7 +133,14 @@ function handleLogin() {
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;
@@ -135,20 +161,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;
@@ -213,7 +225,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,
@@ -232,7 +269,7 @@ window.processOAuthCode = function processOAuthCode(data) {
data: params,
success:function(data, textStatus, jqXHR)
{
onOAuthComplete(data);
onOAuthComplete(data, OAuthSchemeKey);
},
error: function(jqXHR, textStatus, errorThrown)
{
@@ -241,7 +278,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')
@@ -251,11 +288,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_information_panel'), function(k, v) {
var children = v;
if(children && children.childNodes) {
var requiredScopes = [];
@@ -292,7 +332,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'));
}
}
}