From 585635ae6ece1f8b7cd799a7d5db3a77030f4198 Mon Sep 17 00:00:00 2001 From: Corey Wilson Date: Fri, 28 Aug 2015 16:15:16 -0400 Subject: [PATCH 1/4] added basic support for oauth2-password-flow --- lib/swagger-oauth.js | 140 ++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 43 deletions(-) diff --git a/lib/swagger-oauth.js b/lib/swagger-oauth.js index 3bb1c2773ab..483f6a48994 100644 --- a/lib/swagger-oauth.js +++ b/lib/swagger-oauth.js @@ -11,26 +11,33 @@ var scopeSeparator; function handleLogin() { var scopes = []; - var auths = window.swaggerUi.api.authSchemes || window.swaggerUi.api.securityDefinitions; + var auths = window.swaggerUi.api.authSchemes || window.swaggerUi.api.securityDefinitions, + passwordFlow = false; + if(auths) { var key; var defs = auths; 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 - var i; - for(i = 0; i < auth.scopes.length; i++) { - scopes.push(auth.scopes[i]); + if(auth.type === 'oauth2') { + passwordFlow = auth.flow === 'password'; + + if (auth.scopes) { + oauth2KeyName = key; + var scope; + + if(Array.isArray(auth.scopes)) { + // 1.2 support + var i; + for(i = 0; i < auth.scopes.length; i++) { + scopes.push(auth.scopes[i]); + } } - } - else { - // 2.0 support - for(scope in auth.scopes) { - scopes.push({scope: scope, description: auth.scopes[scope]}); + else { + // 2.0 support + for(scope in auth.scopes) { + scopes.push({scope: scope, description: auth.scopes[scope]}); + } } } } @@ -42,22 +49,32 @@ function handleLogin() { appName = window.swaggerUi.api.info.title; } - $('.api-popup-dialog').remove(); - popupDialog = $( - [ - '
', - '
Select OAuth2.0 Scopes
', - '
', - '

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.', - 'Learn how to use', - '

', - '

' + appName + ' API requires the following scopes. Select which ones you want to grant to Swagger UI.

', - '
    ', - '
', - '

', - '
', - '
', - '
'].join('')); + $('.api-popup-dialog').remove(); + + popupDialog = ['
']; + + if (passwordFlow === true) { + popupDialog = popupDialog.concat([ + '
Password Auth
', + '

', + '

' + ]); + } + + popupDialog = $(popupDialog.concat([ + '
Select OAuth2.0 Scopes
', + '
', + '

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.', + 'Learn how to use', + '

', + '

' + appName + ' API requires the following scopes. Select which ones you want to grant to Swagger UI.

', + '
    ', + '
', + '

', + '
', + '
', + '
']).join('')); + $(document.body).append(popupDialog); popup = popupDialog.find('ul.api-popup-scopes').empty(); @@ -98,21 +115,31 @@ function handleLogin() { popupDialog.hide(); var authSchemes = window.swaggerUi.api.authSchemes; + var host = window.location; var pathname = location.pathname.substring(0, location.pathname.lastIndexOf("/")); var defaultRedirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html'; var redirectUrl = window.oAuthRedirectUrl || defaultRedirectUrl; var url = null; + var passwordFlowDetails = null; for (var key in authSchemes) { if (authSchemes.hasOwnProperty(key)) { var flow = authSchemes[key].flow; - if(authSchemes[key].type === 'oauth2' && flow && (flow === 'implicit' || flow === 'accessCode')) { + if (authSchemes[key].type === 'oauth2' && flow) { 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); + + if (flow === 'password') { + passwordFlowDetails = dets; + window.swaggerUi.tokenUrl = dets.tokenUrl; + + } else if (['implicit', 'accessCode'].indexOf(flow) !== -1) { + + url = dets.authorizationUrl + '?response_type=' + (flow === 'implicit' ? 'token' : 'code'); + window.swaggerUi.tokenUrl = (flow === 'accessCode' ? dets.tokenUrl : null); + } } else if(authSchemes[key].grantTypes) { // 1.2 support @@ -144,20 +171,25 @@ function handleLogin() { scopes.push(scope); } - // Implicit auth recommends a state parameter. - var state = Math.random (); + if (passwordFlowDetails !== null) { + handlePasswordFlow(passwordFlowDetails); + + } else { + // Implicit auth recommends a state parameter. + var state = Math.random (); - window.enabledScopes=scopes; + window.enabledScopes=scopes; - redirect_uri = redirectUrl; + redirect_uri = redirectUrl; - url += '&redirect_uri=' + encodeURIComponent(redirectUrl); - url += '&realm=' + encodeURIComponent(realm); - url += '&client_id=' + encodeURIComponent(clientId); - url += '&scope=' + encodeURIComponent(scopes.join(scopeSeparator)); - url += '&state=' + encodeURIComponent(state); + url += '&redirect_uri=' + encodeURIComponent(redirectUrl); + url += '&realm=' + encodeURIComponent(realm); + url += '&client_id=' + encodeURIComponent(clientId); + url += '&scope=' + encodeURIComponent(scopes.join(scopeSeparator)); + url += '&state=' + encodeURIComponent(state); - window.open(url); + window.open(url); + } }); popupMask.show(); @@ -165,6 +197,28 @@ function handleLogin() { return; } +function handlePasswordFlow(auth) { + var tokenUri = auth.tokenUrl; + + var authParams = { + grant_type: 'password', + client_id: encodeURIComponent(clientId), + username: $('#username').val(), + password: encodeURIComponent($('#password').val()), + }; + + $.ajax({ + url: auth.tokenUrl, + type: 'post', + data: authParams, + success: function (data) { + onOAuthComplete(data); + }, + error: function(data) { + onOAuthComplete(""); + } + }); +} function handleLogout() { for(key in window.swaggerUi.api.clientAuthorizations.authz){ From 44561e60d64bcef4a2c46821057dd6476f891a3a Mon Sep 17 00:00:00 2001 From: Corey Wilson Date: Tue, 8 Sep 2015 11:50:29 -0400 Subject: [PATCH 2/4] add in clientSecret to the auth headers --- lib/swagger-oauth.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/swagger-oauth.js b/lib/swagger-oauth.js index 483f6a48994..8cc381348d4 100644 --- a/lib/swagger-oauth.js +++ b/lib/swagger-oauth.js @@ -211,6 +211,9 @@ function handlePasswordFlow(auth) { url: auth.tokenUrl, type: 'post', data: authParams, + headers: { + 'Authorization': 'Basic ' + clientSecret + }, success: function (data) { onOAuthComplete(data); }, From 1d8fde5b43a7c10accecfc6e42c09ba7670f9797 Mon Sep 17 00:00:00 2001 From: Corey Wilson Date: Tue, 8 Sep 2015 20:16:14 -0400 Subject: [PATCH 3/4] added client_secret to the POST params --- lib/swagger-oauth.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/swagger-oauth.js b/lib/swagger-oauth.js index 8cc381348d4..e9172f69ed1 100644 --- a/lib/swagger-oauth.js +++ b/lib/swagger-oauth.js @@ -205,15 +205,13 @@ function handlePasswordFlow(auth) { client_id: encodeURIComponent(clientId), username: $('#username').val(), password: encodeURIComponent($('#password').val()), + client_secret: encodeURIComponent(clientSecret) }; $.ajax({ url: auth.tokenUrl, type: 'post', data: authParams, - headers: { - 'Authorization': 'Basic ' + clientSecret - }, success: function (data) { onOAuthComplete(data); }, From 23ab7ed25e617032caecb5c9b113a8e8dd366c1d Mon Sep 17 00:00:00 2001 From: Corey Wilson Date: Tue, 8 Sep 2015 20:16:22 -0400 Subject: [PATCH 4/4] removed unused variable --- lib/swagger-oauth.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/swagger-oauth.js b/lib/swagger-oauth.js index e9172f69ed1..7dd30352bdf 100644 --- a/lib/swagger-oauth.js +++ b/lib/swagger-oauth.js @@ -198,8 +198,6 @@ function handleLogin() { } function handlePasswordFlow(auth) { - var tokenUri = auth.tokenUrl; - var authParams = { grant_type: 'password', client_id: encodeURIComponent(clientId),