github.com/qubitproducts/logspray@v0.2.14/server/swagger-ui/lib/swagger-oauth.js (about) 1 var appName; 2 var popupMask; 3 var popupDialog; 4 var clientId; 5 var realm; 6 var redirect_uri; 7 var clientSecret; 8 var scopeSeparator; 9 var additionalQueryStringParams; 10 11 function handleLogin() { 12 var scopes = []; 13 14 var auths = window.swaggerUiAuth.authSchemes || window.swaggerUiAuth.securityDefinitions; 15 if(auths) { 16 var key; 17 var defs = auths; 18 for(key in defs) { 19 var auth = defs[key]; 20 if(auth.type === 'oauth2' && auth.scopes) { 21 var scope; 22 if(Array.isArray(auth.scopes)) { 23 // 1.2 support 24 var i; 25 for(i = 0; i < auth.scopes.length; i++) { 26 scopes.push(auth.scopes[i]); 27 } 28 } 29 else { 30 // 2.0 support 31 for(scope in auth.scopes) { 32 scopes.push({scope: scope, description: auth.scopes[scope], OAuthSchemeKey: key}); 33 } 34 } 35 } 36 } 37 } 38 39 if(window.swaggerUi.api && window.swaggerUi.api.info) { 40 appName = window.swaggerUi.api.info.title; 41 } 42 43 $('.api-popup-dialog').remove(); 44 popupDialog = $( 45 [ 46 '<div class="api-popup-dialog">', 47 '<div class="api-popup-title">Select OAuth2.0 Scopes</div>', 48 '<div class="api-popup-content">', 49 '<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.', 50 '<a href="#">Learn how to use</a>', 51 '</p>', 52 '<p><strong>' + appName + '</strong> API requires the following scopes. Select which ones you want to grant to Swagger UI.</p>', 53 '<ul class="api-popup-scopes">', 54 '</ul>', 55 '<p class="error-msg"></p>', 56 '<div class="api-popup-actions"><button class="api-popup-authbtn api-button green" type="button">Authorize</button><button class="api-popup-cancel api-button gray" type="button">Cancel</button></div>', 57 '</div>', 58 '</div>'].join('')); 59 $(document.body).append(popupDialog); 60 61 //TODO: only display applicable scopes (will need to pass them into handleLogin) 62 popup = popupDialog.find('ul.api-popup-scopes').empty(); 63 for (i = 0; i < scopes.length; i ++) { 64 scope = scopes[i]; 65 str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"' +'" oauthtype="' + scope.OAuthSchemeKey +'"/>' + '<label for="scope_' + i + '">' + scope.scope ; 66 if (scope.description) { 67 if ($.map(auths, function(n, i) { return i; }).length > 1) //if we have more than one scheme, display schemes 68 str += '<br/><span class="api-scope-desc">' + scope.description + ' ('+ scope.OAuthSchemeKey+')' +'</span>'; 69 else 70 str += '<br/><span class="api-scope-desc">' + scope.description + '</span>'; 71 } 72 str += '</label></li>'; 73 popup.append(str); 74 } 75 76 var $win = $(window), 77 dw = $win.width(), 78 dh = $win.height(), 79 st = $win.scrollTop(), 80 dlgWd = popupDialog.outerWidth(), 81 dlgHt = popupDialog.outerHeight(), 82 top = (dh -dlgHt)/2 + st, 83 left = (dw - dlgWd)/2; 84 85 popupDialog.css({ 86 top: (top < 0? 0 : top) + 'px', 87 left: (left < 0? 0 : left) + 'px' 88 }); 89 90 popupDialog.find('button.api-popup-cancel').click(function() { 91 popupMask.hide(); 92 popupDialog.hide(); 93 popupDialog.empty(); 94 popupDialog = []; 95 }); 96 97 $('button.api-popup-authbtn').unbind(); 98 popupDialog.find('button.api-popup-authbtn').click(function() { 99 popupMask.hide(); 100 popupDialog.hide(); 101 102 var authSchemes = window.swaggerUi.api.authSchemes; 103 var host = window.location; 104 var pathname = location.pathname.substring(0, location.pathname.lastIndexOf("/")); 105 var defaultRedirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html'; 106 var redirectUrl = window.oAuthRedirectUrl || defaultRedirectUrl; 107 var url = null; 108 var scopes = [] 109 var o = popup.find('input:checked'); 110 var OAuthSchemeKeys = []; 111 var state; 112 for(k =0; k < o.length; k++) { 113 var scope = $(o[k]).attr('scope'); 114 if (scopes.indexOf(scope) === -1) 115 scopes.push(scope); 116 var OAuthSchemeKey = $(o[k]).attr('oauthtype'); 117 if (OAuthSchemeKeys.indexOf(OAuthSchemeKey) === -1) 118 OAuthSchemeKeys.push(OAuthSchemeKey); 119 } 120 121 //TODO: merge not replace if scheme is different from any existing 122 //(needs to be aware of schemes to do so correctly) 123 window.enabledScopes=scopes; 124 125 for (var key in authSchemes) { 126 if (authSchemes.hasOwnProperty(key) && OAuthSchemeKeys.indexOf(key) != -1) { //only look at keys that match this scope. 127 var flow = authSchemes[key].flow; 128 129 if(authSchemes[key].type === 'oauth2' && flow && (flow === 'implicit' || flow === 'accessCode')) { 130 var dets = authSchemes[key]; 131 url = dets.authorizationUrl + '?response_type=' + (flow === 'implicit' ? 'token' : 'code'); 132 window.swaggerUi.tokenName = dets.tokenName || 'access_token'; 133 window.swaggerUi.tokenUrl = (flow === 'accessCode' ? dets.tokenUrl : null); 134 state = key; 135 } 136 else if(authSchemes[key].type === 'oauth2' && flow && (flow === 'application')) { 137 var dets = authSchemes[key]; 138 window.swaggerUi.tokenName = dets.tokenName || 'access_token'; 139 clientCredentialsFlow(scopes, dets.tokenUrl, key); 140 return; 141 } 142 else if(authSchemes[key].grantTypes) { 143 // 1.2 support 144 var o = authSchemes[key].grantTypes; 145 for(var t in o) { 146 if(o.hasOwnProperty(t) && t === 'implicit') { 147 var dets = o[t]; 148 var ep = dets.loginEndpoint.url; 149 url = dets.loginEndpoint.url + '?response_type=token'; 150 window.swaggerUi.tokenName = dets.tokenName; 151 } 152 else if (o.hasOwnProperty(t) && t === 'accessCode') { 153 var dets = o[t]; 154 var ep = dets.tokenRequestEndpoint.url; 155 url = dets.tokenRequestEndpoint.url + '?response_type=code'; 156 window.swaggerUi.tokenName = dets.tokenName; 157 } 158 } 159 } 160 } 161 } 162 163 redirect_uri = redirectUrl; 164 165 url += '&redirect_uri=' + encodeURIComponent(redirectUrl); 166 url += '&realm=' + encodeURIComponent(realm); 167 url += '&client_id=' + encodeURIComponent(clientId); 168 url += '&scope=' + encodeURIComponent(scopes.join(scopeSeparator)); 169 url += '&state=' + encodeURIComponent(state); 170 for (var key in additionalQueryStringParams) { 171 url += '&' + key + '=' + encodeURIComponent(additionalQueryStringParams[key]); 172 } 173 174 window.open(url); 175 }); 176 177 popupMask.show(); 178 popupDialog.show(); 179 return; 180 } 181 182 183 function handleLogout() { 184 for(key in window.swaggerUi.api.clientAuthorizations.authz){ 185 window.swaggerUi.api.clientAuthorizations.remove(key) 186 } 187 window.enabledScopes = null; 188 $('.api-ic.ic-on').addClass('ic-off'); 189 $('.api-ic.ic-on').removeClass('ic-on'); 190 191 // set the info box 192 $('.api-ic.ic-warning').addClass('ic-error'); 193 $('.api-ic.ic-warning').removeClass('ic-warning'); 194 } 195 196 function initOAuth(opts) { 197 var o = (opts||{}); 198 var errors = []; 199 200 appName = (o.appName||errors.push('missing appName')); 201 popupMask = (o.popupMask||$('#api-common-mask')); 202 popupDialog = (o.popupDialog||$('.api-popup-dialog')); 203 clientId = (o.clientId||errors.push('missing client id')); 204 clientSecret = (o.clientSecret||null); 205 realm = (o.realm||errors.push('missing realm')); 206 scopeSeparator = (o.scopeSeparator||' '); 207 additionalQueryStringParams = (o.additionalQueryStringParams||{}); 208 209 if(errors.length > 0){ 210 log('auth unable initialize oauth: ' + errors); 211 return; 212 } 213 214 $('pre code').each(function(i, e) {hljs.highlightBlock(e)}); 215 $('.api-ic').unbind(); 216 $('.api-ic').click(function(s) { 217 if($(s.target).hasClass('ic-off')) 218 handleLogin(); 219 else { 220 handleLogout(); 221 } 222 false; 223 }); 224 } 225 226 function clientCredentialsFlow(scopes, tokenUrl, OAuthSchemeKey) { 227 var params = { 228 'client_id': clientId, 229 'client_secret': clientSecret, 230 'scope': scopes.join(' '), 231 'grant_type': 'client_credentials' 232 } 233 $.ajax( 234 { 235 url : tokenUrl, 236 type: "POST", 237 data: params, 238 success:function(data, textStatus, jqXHR) 239 { 240 onOAuthComplete(data,OAuthSchemeKey); 241 }, 242 error: function(jqXHR, textStatus, errorThrown) 243 { 244 onOAuthComplete(""); 245 } 246 }); 247 248 } 249 250 window.processOAuthCode = function processOAuthCode(data) { 251 var OAuthSchemeKey = data.state; 252 253 // redirect_uri is required in auth code flow 254 // see https://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.1.3 255 var host = window.location; 256 var pathname = location.pathname.substring(0, location.pathname.lastIndexOf("/")); 257 var defaultRedirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html'; 258 var redirectUrl = window.oAuthRedirectUrl || defaultRedirectUrl; 259 260 var params = { 261 'client_id': clientId, 262 'code': data.code, 263 'grant_type': 'authorization_code', 264 'redirect_uri': redirectUrl 265 }; 266 267 if (clientSecret) { 268 params.client_secret = clientSecret; 269 } 270 271 $.ajax( 272 { 273 url : window.swaggerUiAuth.tokenUrl, 274 type: "POST", 275 data: params, 276 success:function(data, textStatus, jqXHR) 277 { 278 onOAuthComplete(data, OAuthSchemeKey); 279 }, 280 error: function(jqXHR, textStatus, errorThrown) 281 { 282 onOAuthComplete(""); 283 } 284 }); 285 }; 286 287 window.onOAuthComplete = function onOAuthComplete(token, OAuthSchemeKey) { 288 if(token) { 289 if(token.error) { 290 var checkbox = $('input[type=checkbox],.secured') 291 checkbox.each(function(pos){ 292 checkbox[pos].checked = false; 293 }); 294 alert(token.error); 295 } 296 else { 297 var b = token[window.swaggerUiAuth.tokenName]; 298 if (!OAuthSchemeKey){ 299 OAuthSchemeKey = token.state; 300 } 301 if(b){ 302 // if all roles are satisfied 303 var o = null; 304 $.each($('.auth .api-ic .api_information_panel'), function(k, v) { 305 var children = v; 306 if(children && children.childNodes) { 307 var requiredScopes = []; 308 $.each((children.childNodes), function (k1, v1){ 309 var inner = v1.innerHTML; 310 if(inner) 311 requiredScopes.push(inner); 312 }); 313 var diff = []; 314 for(var i=0; i < requiredScopes.length; i++) { 315 var s = requiredScopes[i]; 316 if(window.enabledScopes && window.enabledScopes.indexOf(s) == -1) { 317 diff.push(s); 318 } 319 } 320 if(diff.length > 0){ 321 o = v.parentNode.parentNode; 322 $(o.parentNode).find('.api-ic.ic-on').addClass('ic-off'); 323 $(o.parentNode).find('.api-ic.ic-on').removeClass('ic-on'); 324 325 // sorry, not all scopes are satisfied 326 $(o).find('.api-ic').addClass('ic-warning'); 327 $(o).find('.api-ic').removeClass('ic-error'); 328 } 329 else { 330 o = v.parentNode.parentNode; 331 $(o.parentNode).find('.api-ic.ic-off').addClass('ic-on'); 332 $(o.parentNode).find('.api-ic.ic-off').removeClass('ic-off'); 333 334 // all scopes are satisfied 335 $(o).find('.api-ic').addClass('ic-info'); 336 $(o).find('.api-ic').removeClass('ic-warning'); 337 $(o).find('.api-ic').removeClass('ic-error'); 338 } 339 } 340 }); 341 if(typeof window.swaggerUi !== 'undefined') { 342 window.swaggerUi.api.clientAuthorizations.add(window.swaggerUiAuth.OAuthSchemeKey, new SwaggerClient.ApiKeyAuthorization('Authorization', 'Bearer ' + b, 'header')); 343 window.swaggerUi.load(); 344 } 345 } 346 } 347 } 348 };