You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ja...@apache.org on 2018/10/09 09:09:24 UTC

[20/27] lucene-solr:solr7896-login-page: New iteration. Intercepts WWW-authenticate header and allows separate screens per type WORK IN PROGRESS

New iteration. Intercepts WWW-authenticate header and allows separate screens per type
WORK IN PROGRESS


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/9012e40a
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/9012e40a
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/9012e40a

Branch: refs/heads/solr7896-login-page
Commit: 9012e40a5c2afd8bd8f482ea208d255da1af6e76
Parents: 9ee3506
Author: Jan Høydahl <ja...@apache.org>
Authored: Fri Oct 5 16:41:25 2018 +0200
Committer: Jan Høydahl <ja...@apache.org>
Committed: Fri Oct 5 16:41:25 2018 +0200

----------------------------------------------------------------------
 .../apache/solr/security/BasicAuthPlugin.java   |   6 +
 solr/webapp/web/index.html                      |   5 +-
 solr/webapp/web/js/angular/app.js               | 117 +++++++++++--------
 solr/webapp/web/js/angular/controllers/login.js |  38 ++++--
 solr/webapp/web/js/angular/services.js          |  22 +++-
 solr/webapp/web/partials/login.html             |  33 +++++-
 6 files changed, 151 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/9012e40a/solr/core/src/java/org/apache/solr/security/BasicAuthPlugin.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/security/BasicAuthPlugin.java b/solr/core/src/java/org/apache/solr/security/BasicAuthPlugin.java
index 3533b9e..597df7c 100644
--- a/solr/core/src/java/org/apache/solr/security/BasicAuthPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/BasicAuthPlugin.java
@@ -108,6 +108,12 @@ public class BasicAuthPlugin extends AuthenticationPlugin implements ConfigEdita
       }
       response.setHeader(entry.getKey(), value);
     }
+    // NOCOMMIT - which headers to set?
+    // Need to explicitly allow Admin UI to read these headers from the 401 response
+//    response.setHeader("Access-Control-Expose-Headers", "WWW-Authenticate, X-Solr-AuthData");
+//    response.setHeader("Access-Control-Allow-Origin", "*");
+//    response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE");
+//    response.setHeader("Access-Control-Max-Age", "3600");
     response.sendError(401, message);
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/9012e40a/solr/webapp/web/index.html
----------------------------------------------------------------------
diff --git a/solr/webapp/web/index.html b/solr/webapp/web/index.html
index d832155..4b83533 100644
--- a/solr/webapp/web/index.html
+++ b/solr/webapp/web/index.html
@@ -64,9 +64,6 @@ limitations under the License.
   <script src="libs/jquery-ui.min.js"></script>
   <script src="js/angular/app.js"></script>
   <script src="js/angular/services.js"></script>
-  <script src="js/angular/directives.js"></script>
-  <script src="js/angular/http-auth-interceptor.js"></script>
-  <script src="js/angular/login-controllers.js"></script>
   <script src="js/angular/controllers/index.js"></script>
   <script src="js/angular/controllers/login.js"></script>
   <script src="js/angular/controllers/logging.js"></script>
@@ -144,7 +141,7 @@ limitations under the License.
         <div>
 
           <ul id="menu">
-            <li id="login" class="global" ng-class="{active:page=='login'}"><p><a href="#/login">Logout</a></p></li>
+            <li id="login" class="global" ng-class="{active:page=='login'}"><p><a href="#/login">Logout {{username}}</a></p></li>
             
             <li id="index" class="global" ng-class="{active:page=='index'}"><p><a href="#/">Dashboard</a></p></li>
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/9012e40a/solr/webapp/web/js/angular/app.js
----------------------------------------------------------------------
diff --git a/solr/webapp/web/js/angular/app.js b/solr/webapp/web/js/angular/app.js
index 71dd98b..36dd07c 100644
--- a/solr/webapp/web/js/angular/app.js
+++ b/solr/webapp/web/js/angular/app.js
@@ -369,66 +369,85 @@ solrAdminApp.config([
       $rootScope.exceptions[rejection.config.url] = rejection.data.error;
     }
     return $q.reject(rejection);
-  }
+  };
 
   return {request: started, response: ended, responseError: failed};
 })
 // NOCOMMIT First iteration    
-// .factory('authInterceptor', function($q, $rootScope, $timeout, $injector) {
-//   var started = function(config) {
-//     var ah = "Basic c29scjpyb2Nrcw==";  // solr / SolrRocks
-//     config.headers['Authorization'] = ah;
-//     console.log("Added authorization header " + ah);
-//     return config || $q.when(config);
-//   };
-//
-//   var ended = function(response) {
-//     console.log("Response headers: " + JSON.stringify(response.headers, undefined, 2));
-//     if (response.headers['WWW-Authenticate'] != null) {
-//       console.log("Got WWW-Authenticate header: " + response.headers['WWW-Authenticate']);
-//     }
-//     return response || $q.when(response);
-//   };
-//
-//   var failed = function(rejection) {
-//     console.log("Failed with rejection " + JSON.stringify(rejection, undefined, 2));
-//     if (rejection.status === 401) {
-//       console.log("Status code is 401");
-//     } else {
-//       console.log("Rejection status is " + rejection.status)
-//     }
-//     $rootScope.$broadcast('loadingStatusInactive');
-//     return $q.reject(rejection);
-//   };
-//
-//   return {request: started, response: ended, responseError: failed};
-// })
+.factory('authInterceptor', function($q, $rootScope, $location, $timeout, $injector) {
+  var started = function(config) {
+    console.log("Request config: " + JSON.stringify(config, undefined, 2));
+    // var ah = "Basic c29scjpyb2Nrcw==";  // solr / SolrRocks
+    // config.headers['Authorization'] = ah;
+    // console.log("Added authorization header " + ah);
+    if (sessionStorage.getItem("auth.header") !== null) {
+      if (config.headers['Authorization'] === null) {
+        config.headers['Authorization'] = sessionStorage.getItem("auth.header");
+        console.log("We have a logged in user with header " + sessionStorage.getItem("auth.username") + ", appending header");
+      }
+    }
+    return config || $q.when(config);
+  };
+
+  var ended = function(response) {
+    console.log("Response headers: " + JSON.stringify(response.headers(), undefined, 2));
+    return response || $q.when(response);
+  };
+
+  var failed = function(rejection) {
+    console.log("Failed with rejection " + JSON.stringify(rejection, undefined, 2));
+    if (rejection.status === 401) {
+      console.log("Status code is 401");
+      var headers = rejection.headers();
+      console.log("Headers are " + JSON.stringify(headers, undefined, 2));
+      var wwwAuthHeader = headers['www-authenticate'];
+      sessionStorage.setItem("auth.wwwAuthHeader", wwwAuthHeader);
+      var authDataHeader = headers['X-Solr-AuthData'];
+      if (authDataHeader !== null) {
+        sessionStorage.setItem("auth.config", authDataHeader);
+      }
+      console.log("Got WWW-Authenticate header: " + wwwAuthHeader + " and X-Solr-AuthData: " + authDataHeader);
+      var authType = wwwAuthHeader.split(" ")[0];
+      console.log("AuthType is: " + authType);
+      sessionStorage.setItem("auth.type", authType);
+      sessionStorage.setItem("auth.location", $location.path());
+      sessionStorage.removeItem("auth.username");
+      sessionStorage.removeItem("auth.header");
+      $location.path('/login');
+    } else {
+      console.log("Rejection status is " + rejection.status)
+    }
+    $rootScope.$broadcast('loadingStatusInactive');
+    return $q.reject(rejection);
+  };
+
+  return {request: started, response: ended, responseError: failed};
+})
 .config(function($httpProvider) {
   $httpProvider.interceptors.push("httpInterceptor");
-  // NOCOMMIT $httpProvider.interceptors.push("authInterceptor");
-  // Tell the BasicAuth plugin that we are Admin UI so it can serve us a 'Authorization: xBasic xxxx' header
-  // so that the browser will not interfer with the login dialogue
+  $httpProvider.interceptors.push("authInterceptor");
+  // Force BasicAuth plugin to serve us a 'Authorization: xBasic xxxx' header so browser will not pop up login dialogue
   $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
 })
     
     
 // NOCOMMIT: just for testing     
-.run(['$rootScope', '$location', '$cookieStore', '$http',
-  function ($rootScope, $location, $cookieStore, $http) {
-    // keep user logged in after page refresh
-    // Replace with interceptor
-    $rootScope.globals = $cookieStore.get('globals') || {};
-    if ($rootScope.globals.currentUser) {
-      $http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata; // jshint ignore:line
-    }
-
-    $rootScope.$on('$locationChangeStart', function (event, next, current) {
-      // redirect to login page if not logged in
-      if ($location.path() !== '/login' && !$rootScope.globals.currentUser) {
-        $location.path('/login');
-      }
-    });
-  }])
+// .run(['$rootScope', '$location', '$cookieStore', '$http',
+//   function ($rootScope, $location, $cookieStore, $http) {
+//     // keep user logged in after page refresh
+//     // Replace with interceptor
+//     $rootScope.globals = $cookieStore.get('globals') || {};
+//     if ($rootScope.globals.currentUser) {
+//       $http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata; // jshint ignore:line
+//     }
+//
+//     // $rootScope.$on('$locationChangeStart', function (event, next, current) {
+//     //   // redirect to login page if not logged in
+//     //   if ($location.path() !== '/login' && !$rootScope.globals.currentUser) {
+//     //     $location.path('/login');
+//     //   }
+//     // });
+//   }])
 
     
 .directive('fileModel', function ($parse) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/9012e40a/solr/webapp/web/js/angular/controllers/login.js
----------------------------------------------------------------------
diff --git a/solr/webapp/web/js/angular/controllers/login.js b/solr/webapp/web/js/angular/controllers/login.js
index 653ca14..a67119c8 100644
--- a/solr/webapp/web/js/angular/controllers/login.js
+++ b/solr/webapp/web/js/angular/controllers/login.js
@@ -16,15 +16,28 @@
 */
 
 solrAdminApp.controller('LoginController',
-    ['$scope', '$rootScope', '$location', 'AuthenticationService',
-      function ($scope, $rootScope, $location, AuthenticationService) {
-        // reset login status
-        AuthenticationService.ClearCredentials();
-
+    ['$scope', '$routeParams', '$rootScope', '$location', 'AuthenticationService',
+      function ($scope, $routeParams, $rootScope, $location, AuthenticationService) {
+        var authType = sessionStorage.getItem("auth.type");
+        var basicTypes = ['Basic', 'xBasic'];
+        if (authType !== null && basicTypes.includes(authType)) {
+          if (authType === 'xBasic') authType = 'Basic';
+          $scope.authType = authType;
+        } else {
+          $scope.authType = 'unknown';
+        }      
+        
+        $scope.wwwAuthHeader = sessionStorage.getItem("auth.wwwAuthHeader");
+        $scope.authConfig = sessionStorage.getItem("auth.config");
+        $scope.authLocation = sessionStorage.getItem("auth.location");
+        $scope.authLoggedinUser = sessionStorage.getItem("auth.username");
+        $scope.authHeader = sessionStorage.getItem("auth.header");
+        
         $scope.login = function () {
-          $scope.dataLoading = true;
           AuthenticationService.SetCredentials($scope.username, $scope.password);
-          $location.path('/');
+          console.log("Redirecting back to " + $scope.authLocation);
+          $location.path($scope.authLocation); // Redirect to the location that caused the login prompt
+          
           // TODO: "login" by hitting the failing URL again
           // AuthenticationService.Login($scope.username, $scope.password, function (response) {
           //   if (response.success) {
@@ -36,4 +49,15 @@ solrAdminApp.controller('LoginController',
           //   }
           // });
         };
+        
+        $scope.logout = function() {
+          // reset login status
+          AuthenticationService.ClearCredentials();
+          console.log("Logged out user and cleared creds");
+          $location.path("/");
+        };
+        
+        $scope.isLoggedIn = function() {
+          return (sessionStorage.getItem("auth.username") !== null);
+        };
       }]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/9012e40a/solr/webapp/web/js/angular/services.js
----------------------------------------------------------------------
diff --git a/solr/webapp/web/js/angular/services.js b/solr/webapp/web/js/angular/services.js
index b6df864..323bc8e 100644
--- a/solr/webapp/web/js/angular/services.js
+++ b/solr/webapp/web/js/angular/services.js
@@ -264,8 +264,8 @@ solrAdminServices.factory('System',
      })
 }])
 .factory('AuthenticationService',
-    ['Base64', '$http', '$cookieStore', '$rootScope', '$timeout',
-      function (Base64, $http, $cookieStore, $rootScope, $timeout) {
+    ['Base64', '$http', '$rootScope', '$timeout',
+      function (Base64, $http, $rootScope, $timeout) {
         var service = {};
 
         service.Login = function (username, password, callback) {
@@ -293,6 +293,9 @@ solrAdminServices.factory('System',
         service.SetCredentials = function (username, password) {
           var authdata = Base64.encode(username + ':' + password);
 
+          sessionStorage.setItem("auth.username", username);
+          $rootScope.username = username;
+
           $rootScope.globals = {
             currentUser: {
               username: username,
@@ -300,14 +303,21 @@ solrAdminServices.factory('System',
             }
           };
 
-          $http.defaults.headers.common['Authorization'] = 'Basic ' + authdata; // jshint ignore:line
-          $cookieStore.put('globals', $rootScope.globals);
+          // $http.defaults.headers.common['Authorization'] = 'Basic ' + authdata; // jshint ignore:line
+          $http.defaults.headers.common.Authorization = 'Basic ' + authdata;
+          // sessionStorage.setItem('globals', $rootScope.globals);
+          sessionStorage.setItem("auth.header", authdata);
+          console.log("Stored auth data on session storage");
         };
 
         service.ClearCredentials = function () {
           $rootScope.globals = {};
-          $cookieStore.remove('globals');
-          $http.defaults.headers.common.Authorization = 'Basic ';
+          // sessionStorage.removeItem('globals');
+          sessionStorage.removeItem("auth.header");
+          sessionStorage.removeItem("auth.username");
+          sessionStorage.removeItem("auth.wwwAuthHeader");
+          $http.defaults.headers.common.Authorization = null;
+          console.log("Cleared stored auth data");
         };
 
         return service;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/9012e40a/solr/webapp/web/partials/login.html
----------------------------------------------------------------------
diff --git a/solr/webapp/web/partials/login.html b/solr/webapp/web/partials/login.html
index 65be563..37768cf 100644
--- a/solr/webapp/web/partials/login.html
+++ b/solr/webapp/web/partials/login.html
@@ -15,12 +15,18 @@ See the License for the specific language governing permissions and
 limitations under the License.
 -->
 <div id="login">
-  <div class="col-xs-offset-2 col-xs-8">
-    <h1>Please log in</h1>
-    Basic Authentication 
+
+  <div class="col-xs-offset-2 col-xs-8" ng-show="authType === 'Basic'">
+    <h1>Basic Authentication</h1>     
     
+    <p>Type: {{authType}}</p>
+    <p>WWW-Header: {{wwwAuthHeader}}</p>
+    <p>Config: {{authConfig}}</p>
+    <p>Redirect: {{authLocation}}</p>
+    <p>LoggedinUser: {{authLoggedinUser}}</p>
+
     <div ng-show="error" class="alert alert-danger">{{error}}</div>
-    <form name="form" ng-submit="login()" role="form">
+    <form name="form" ng-submit="login()" role="form" ng-show="!isLoggedIn()">
         <div class="form-group">
             <label for="username">Username</label>
             <i class="fa fa-key"></i>
@@ -38,5 +44,24 @@ limitations under the License.
             <img ng-if="dataLoading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
         </div>
     </form>
+    <form name="logoutForm" ng-submit="logout()" role="form" ng-show="isLoggedIn()">
+        <div class="form-actions">
+            <button type="submit" class="btn btn-danger">Logout</button>
+        </div>
+    </form>
+    
+  </div>
+  
+  
+  <div class="col-xs-offset-2 col-xs-8" ng-show="authType === 'unknown'">
+    <h1>Authentication type not supported</h1>     
+    
+    <p>Type: {{authType}}</p>
+    <p>WWW-Header: {{wwwAuthHeader}}</p>
+    <p>Config: {{authConfig}}</p>
+    <p>Redirect: {{authLocation}}</p>
+    <p>LoggedinUser: {{authLoggedinUser}}</p>
+
+    You cannot use Solr's Admin UI for this operation. Please use another client that supports this type. 
   </div>
 </div>