diff options
author | server <brownptcdash@gmail.com> | 2019-12-10 18:12:37 -0500 |
---|---|---|
committer | server <brownptcdash@gmail.com> | 2019-12-10 18:12:37 -0500 |
commit | 7478e610d99d1f2fb383ecbfa0b70d72eae27f81 (patch) | |
tree | 59486701838067351f00580315c05690f36a39ce /solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/login.js | |
parent | 096718ee546afbd7568bf8ec9e23dca0556d814d (diff) |
solr changes
Diffstat (limited to 'solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/login.js')
-rw-r--r-- | solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/login.js | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/login.js b/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/login.js new file mode 100644 index 000000000..8127c6fda --- /dev/null +++ b/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/login.js @@ -0,0 +1,317 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +solrAdminApp.controller('LoginController', + ['$scope', '$routeParams', '$rootScope', '$location', '$window', 'AuthenticationService', 'Constants', + function ($scope, $routeParams, $rootScope, $location, $window, AuthenticationService, Constants) { + $scope.resetMenu("login", Constants.IS_ROOT_PAGE); + $scope.subPath = $routeParams.route; + $rootScope.exceptions = {}; + + // Session variables set in app.js 401 interceptor + var wwwAuthHeader = sessionStorage.getItem("auth.wwwAuthHeader"); + var authScheme = sessionStorage.getItem("auth.scheme"); + if (wwwAuthHeader) { + // Parse www-authenticate header + var wwwHeader = wwwAuthHeader.match(/(\w+)(\s+)?(.*)/); + authScheme = "unknown"; + var authParams = {}; + if (wwwHeader && wwwHeader.length >= 1) + authScheme = wwwHeader[1]; + if (wwwHeader && wwwHeader.length >= 3) + authParams = www_auth_parse_params(wwwHeader[3]); + if (typeof authParams === 'string' || authParams instanceof String) { + $scope.authParamsError = authParams; + } else { + $scope.authParamsError = undefined; + } + var realm = authParams['realm']; + sessionStorage.setItem("auth.realm", realm); + if (authScheme === 'Basic' || authScheme === 'xBasic') { + authScheme = 'Basic'; + } + sessionStorage.setItem("auth.scheme", authScheme); + } + + var supportedSchemes = ['Basic', 'Bearer', 'Negotiate']; + $scope.authSchemeSupported = supportedSchemes.includes(authScheme); + + if (authScheme === 'Bearer') { + // Check for OpenId redirect response + var errorText = ""; + $scope.isCallback = false; + if ($scope.subPath === 'callback') { + $scope.isCallback = true; + var hash = $location.hash(); + var hp = AuthenticationService.decodeHashParams(hash); + var expectedState = sessionStorage.getItem("auth.stateRandom") + "_" + sessionStorage.getItem("auth.location"); + sessionStorage.setItem("auth.state", "error"); + if (hp['access_token'] && hp['token_type'] && hp['state']) { + // Validate state + if (hp['state'] !== expectedState) { + $scope.error = "Problem with auth callback"; + console.log("Expected state param " + expectedState + " but got " + hp['state']); + errorText += "Invalid values in state parameter. "; + } + // Validate token type + if (hp['token_type'].toLowerCase() !== "bearer") { + console.log("Expected token_type param 'bearer', but got " + hp['token_type']); + errorText += "Invalid values in token_type parameter. "; + } + // Unpack ID token and validate nonce, get username + if (hp['id_token']) { + var idToken = hp['id_token'].split("."); + if (idToken.length === 3) { + var payload = AuthenticationService.decodeJwtPart(idToken[1]); + if (!payload['nonce'] || payload['nonce'] !== sessionStorage.getItem("auth.nonce")) { + errorText += "Invalid 'nonce' value, possible attack detected. Please log in again. "; + } + + if (errorText === "") { + sessionStorage.setItem("auth.username", payload['sub']); + sessionStorage.setItem("auth.header", "Bearer " + hp['access_token']); + sessionStorage.removeItem("auth.statusText"); + sessionStorage.removeItem("auth.stateRandom"); + sessionStorage.removeItem("auth.wwwAuthHeader"); + console.log("User " + payload['sub'] + " is logged in"); + var redirectTo = sessionStorage.getItem("auth.location"); + console.log("Redirecting to stored location " + redirectTo); + sessionStorage.setItem("auth.state", "authenticated"); + sessionStorage.removeItem("http401"); + $location.path(redirectTo).hash(""); + } + } else { + console.log("Expected JWT compact id_token param but got " + idToken); + errorText += "Invalid values in id_token parameter. "; + } + } else { + console.log("Callback was missing the id_token parameter, could not validate nonce."); + errorText += "Callback was missing the id_token parameter, could not validate nonce. "; + } + if (hp['access_token'].split(".").length !== 3) { + console.log("Expected JWT compact access_token param but got " + hp['access_token']); + errorText += "Invalid values in access_token parameter. "; + } + if (errorText !== "") { + $scope.error = "Problems with OpenID callback"; + $scope.errorDescription = errorText; + $scope.http401 = "true"; + } + // End callback processing + } else if (hp['error']) { + // The callback had errors + console.log("Error received from idp: " + hp['error']); + var errorDescriptions = {}; + errorDescriptions['invalid_request'] = "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed."; + errorDescriptions['unauthorized_client'] = "The client is not authorized to request an access token using this method."; + errorDescriptions['access_denied'] = "The resource owner or authorization server denied the request."; + errorDescriptions['unsupported_response_type'] = "The authorization server does not support obtaining an access token using this method."; + errorDescriptions['invalid_scope'] = "The requested scope is invalid, unknown, or malformed."; + errorDescriptions['server_error'] = "The authorization server encountered an unexpected condition that prevented it from fulfilling the request."; + errorDescriptions['temporarily_unavailable'] = "The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server."; + $scope.error = "Callback from Id Provider contained error. "; + if (hp['error_description']) { + $scope.errorDescription = decodeURIComponent(hp['error_description']); + } else { + $scope.errorDescription = errorDescriptions[hp['error']]; + } + if (hp['error_uri']) { + $scope.errorDescription += " More information at " + hp['error_uri'] + ". "; + } + if (hp['state'] !== expectedState) { + $scope.errorDescription += "The state parameter returned from ID Provider did not match the one we sent."; + } + sessionStorage.setItem("auth.state", "error"); + } + } + } + + if (errorText === "" && !$scope.error && authParams) { + $scope.error = authParams['error']; + $scope.errorDescription = authParams['error_description']; + $scope.authData = AuthenticationService.getAuthDataHeader(); + } + + $scope.authScheme = sessionStorage.getItem("auth.scheme"); + $scope.authRealm = sessionStorage.getItem("auth.realm"); + $scope.wwwAuthHeader = sessionStorage.getItem("auth.wwwAuthHeader"); + $scope.statusText = sessionStorage.getItem("auth.statusText"); + $scope.authLocation = sessionStorage.getItem("auth.location"); + $scope.authLoggedinUser = sessionStorage.getItem("auth.username"); + $scope.authHeader = sessionStorage.getItem("auth.header"); + + $scope.login = function () { + AuthenticationService.SetCredentials($scope.username, $scope.password); + $location.path($scope.authLocation); // Redirect to the location that caused the login prompt + }; + + $scope.logout = function() { + // reset login status + AuthenticationService.ClearCredentials(); + $location.path("/"); + }; + + $scope.jwtLogin = function () { + var stateRandom = Math.random().toString(36).substr(2); + sessionStorage.setItem("auth.stateRandom", stateRandom); + var authState = stateRandom + "_" + sessionStorage.getItem("auth.location"); + var authNonce = Math.random().toString(36).substr(2) + Math.random().toString(36).substr(2) + Math.random().toString(36).substr(2); + sessionStorage.setItem("auth.nonce", authNonce); + var params = { + "response_type" : "id_token token", + "client_id" : $scope.authData['client_id'], + "redirect_uri" : $window.location.href.split('#')[0], + "scope" : "openid " + $scope.authData['scope'], + "state" : authState, + "nonce" : authNonce + }; + + var endpointBaseUrl = $scope.authData['authorizationEndpoint']; + var loc = endpointBaseUrl + "?" + paramsToString(params); + console.log("Redirecting to " + loc); + sessionStorage.setItem("auth.state", "expectCallback"); + $window.location.href = loc; + + function paramsToString(params) { + var arr = []; + for (var p in params) { + if( params.hasOwnProperty(p) ) { + arr.push(p + "=" + encodeURIComponent(params[p])); + } + } + return arr.join("&"); + } + }; + + $scope.jwtIsLoginNode = function() { + var redirect = $scope.authData ? $scope.authData['redirect_uris'] : undefined; + if (redirect && Array.isArray(redirect) && redirect.length > 0) { + var isLoginNode = false; + redirect.forEach(function(uri) { // Check that current node URL is among the configured callback URIs + if ($window.location.href.startsWith(uri)) isLoginNode = true; + }); + return isLoginNode; + } else { + return true; // no redirect UIRs configured, all nodes are potential login nodes + } + }; + + $scope.jwtFindLoginNode = function() { + var redirect = $scope.authData ? $scope.authData['redirect_uris'] : undefined; + if (redirect && Array.isArray(redirect) && redirect.length > 0) { + var loginNode = redirect[0]; + redirect.forEach(function(uri) { // if current node is in list, return its callback uri + if ($window.location.href.startsWith(uri)) loginNode = uri; + }); + return loginNode; + } else { + return $window.location.href.split('#')[0]; // Return base url of current URL as the url to use + } + }; + + // Redirect to login node if this is not a valid one + $scope.jwtGotoLoginNode = function() { + if (!$scope.jwtIsLoginNode()) { + $window.location.href = $scope.jwtFindLoginNode(); + } + }; + + $scope.jwtLogout = function() { + // reset login status + AuthenticationService.ClearCredentials(); + $location.path("/"); + }; + + $scope.isLoggedIn = function() { + return (sessionStorage.getItem("auth.username") !== null); + }; + }]); + +// This function is copied and adapted from MIT-licensed https://github.com/randymized/www-authenticate/blob/master/lib/parsers.js +www_auth_parse_params= function (header) { + // This parser will definitely fail if there is more than one challenge + var params = {}; + var tok, last_tok, _i, _len, key, value; + var state= 0; //0: token, + var m= header.split(/([",=])/); + for (_i = 0, _len = m.length; _i < _len; _i++) { + last_tok= tok; + tok = m[_i]; + if (!tok.length) continue; + switch (state) { + case 0: // token + key= tok.trim(); + state= 1; // expect equals + continue; + case 1: // expect equals + if ('=' != tok) return 'Equal sign was expected after '+key; + state= 2; + continue; + case 2: // expect value + if ('"' == tok) { + value= ''; + state= 3; // expect quoted + continue; + } + else { + params[key]= value= tok.trim(); + state= 9; // expect comma or end + continue; + } + case 3: // handling quoted string + if ('"' == tok) { + state= 8; // end quoted + continue; + } + else { + value+= tok; + state= 3; // continue accumulating quoted string + continue; + } + case 8: // end quote encountered + if ('"' == tok) { + // double quoted + value+= '"'; + state= 3; // back to quoted string + continue; + } + if (',' == tok) { + params[key]= value; + state= 0; + continue; + } + else { + return 'Unexpected token ('+tok+') after '+value+'"'; + } + continue; + case 9: // expect commma + if (',' != tok) return 'Comma expected after '+value; + state= 0; + continue; + } + } + switch (state) { // terminal state + case 0: // Empty or ignoring terminal comma + case 9: // Expecting comma or end of header + return params; + case 8: // Last token was end quote + params[key]= value; + return params; + default: + return 'Unexpected end of www-authenticate value.'; + } +}; |