From b745779e155c6e60353ac78e1da21389af2409b3 Mon Sep 17 00:00:00 2001 From: Tom Demeranville Date: Fri, 18 Dec 2015 15:58:19 +0000 Subject: [PATCH] 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:
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); --- lib/swagger-oauth.js | 94 +++++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/lib/swagger-oauth.js b/lib/swagger-oauth.js index 9ce42427..f782281b 100644 --- a/lib/swagger-oauth.js +++ b/lib/swagger-oauth.js @@ -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() { ''].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 = '
  • ' + '
  • ' + '
  • '; 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')); } } }