Jelajahi Sumber

AMBARI-13419. Implement forced logout based on user inactivity (rzang)

Richard Zang 10 tahun lalu
induk
melakukan
55645640db

+ 38 - 1
ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/mainCtrl.js

@@ -18,7 +18,7 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('MainCtrl',['$scope', '$window','Auth', 'Alert', '$modal', 'Cluster', 'View', function($scope, $window, Auth, Alert, $modal, Cluster, View) {
+.controller('MainCtrl',['$scope','$rootScope','$window','Auth', 'Alert', '$modal', 'Cluster', 'View', function($scope, $rootScope, $window, Auth, Alert, $modal, Cluster, View) {
   $scope.signOut = function() {
     var data = JSON.parse(localStorage.ambari);
     delete data.app.authenticated;
@@ -87,5 +87,42 @@ angular.module('ambariAdminConsole')
     $scope.updateInstances();
   });
 
+  $scope.startInactiveTimeoutMonitoring = function(timeout) {
+    var TIME_OUT = timeout;
+    var active = true;
+    var lastActiveTime = Date.now();
+
+    var keepActive = function() {
+      //console.error('keepActive');
+      if (active) {
+        lastActiveTime = Date.now();
+      }
+    };
+
+    $(window).bind('mousemove', keepActive);
+    $(window).bind('keypress', keepActive);
+    $(window).bind('click', keepActive);
+
+    var checkActiveness = function() {
+      //console.error("checkActiveness " + lastActiveTime + " : " + Date.now());
+      if (Date.now() - lastActiveTime > TIME_OUT) {
+        //console.error("LOGOUT!");
+        active = false;
+        $(window).unbind('mousemove', keepActive);
+        $(window).unbind('keypress', keepActive);
+        $(window).unbind('click', keepActive);
+        clearInterval($rootScope.userActivityTimeoutInterval);
+        $scope.signOut();
+      }
+    };
+    $rootScope.userActivityTimeoutInterval = window.setInterval(checkActiveness, 1000);
+  };
+
+  if (!$rootScope.userActivityTimeoutInterval) {
+    Cluster.getAmbariTimeout().then(function(timeout) {
+      if (Number(timeout) > 0)
+        $scope.startInactiveTimeoutMonitoring(timeout * 1000);
+    });
+  }
   $scope.updateInstances();
 }]);

+ 13 - 0
ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js

@@ -60,6 +60,19 @@ angular.module('ambariAdminConsole')
 
       return deferred.promise;
     },
+    getAmbariTimeout: function() {
+      var deferred = $q.defer();
+      var url = '/services/AMBARI/components/AMBARI_SERVER?fields=RootServiceComponents/properties/user.inactivity.timeout.default'
+      $http.get(Settings.baseUrl + url)
+      .then(function(data) {
+        deferred.resolve(data.data.RootServiceComponents.properties['user.inactivity.timeout.default']);
+      })
+      .catch(function(data) {
+        deferred.reject(data);
+      });
+
+      return deferred.promise;
+    },
     getPermissions: function() {
       var deferred = $q.defer();
 

+ 1 - 0
ambari-web/app/controllers/global/cluster_controller.js

@@ -370,6 +370,7 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
     this.set('ambariProperties', data.RootServiceComponents.properties);
     // Absence of 'jdk.name' and 'jce.name' properties says that ambari configured with custom jdk.
     this.set('isCustomJDK', App.isEmptyObject(App.permit(data.RootServiceComponents.properties, ['jdk.name', 'jce.name'])));
+    App.router.get('mainController').monitorInactivity();
   },
 
   loadAmbariPropertiesError: function () {

+ 95 - 9
ambari-web/app/controllers/main.js

@@ -21,6 +21,10 @@ require('models/background_operation');
 
 App.MainController = Em.Controller.extend({
   name: 'mainController',
+  isUserActive: true,
+  checkActivenessInterval: null,
+  lastUserActiveTime: null,
+  userTimeOut: 0,
 
   updateTitle: function(){
     var name = App.router.get('clusterController.clusterName');
@@ -109,11 +113,11 @@ App.MainController = Em.Controller.extend({
     clearTimeout(this.get("reloadTimeOut"));
 
     this.set('reloadTimeOut',
-        setTimeout(function () {
-          if (App.clusterStatus.get('isInstalled')) {
-            location.reload();
-          }
-        }, App.pageReloadTime)
+    setTimeout(function () {
+      if (App.clusterStatus.get('isInstalled')) {
+        location.reload();
+      }
+    }, App.pageReloadTime)
     );
   }.observes("App.router.location.lastSetURL", "App.clusterStatus.isInstalled"),
 
@@ -124,17 +128,17 @@ App.MainController = Em.Controller.extend({
   isAllServicesInstalled: function() {
     return this.scRequest('isAllServicesInstalled');
   }.property('App.router.mainServiceController.content.content.@each',
-      'App.router.mainServiceController.content.content.length'),
+  'App.router.mainServiceController.content.content.length'),
 
   isStartAllDisabled: function() {
     return this.scRequest('isStartAllDisabled');
   }.property('App.router.mainServiceController.isStartStopAllClicked',
-      'App.router.mainServiceController.content.@each.healthStatus'),
+  'App.router.mainServiceController.content.@each.healthStatus'),
 
   isStopAllDisabled: function() {
     return this.scRequest('isStopAllDisabled');
   }.property('App.router.mainServiceController.isStartStopAllClicked',
-      'App.router.mainServiceController.content.@each.healthStatus'),
+  'App.router.mainServiceController.content.@each.healthStatus'),
 
   gotoAddService: function() {
     App.router.get('mainServiceController').gotoAddService();
@@ -184,6 +188,88 @@ App.MainController = Em.Controller.extend({
   },
   getServerVersionErrorCallback: function () {
     console.log('ERROR: Cannot load Ambari server version');
-  }
+  },
+
+  monitorInactivity: function() {
+    //console.error('======MONITOR==START========');
+    var timeout = Number(App.router.get('clusterController.ambariProperties')['user.inactivity.timeout.default']);
+    var readonly_timeout = Number(App.router.get('clusterController.ambariProperties')['user.inactivity.timeout.role.readonly.default']);
+    var isAdmin = App.get('isAdmin');
+    if (isAdmin && timeout > 0) {
+      this.set('userTimeOut', timeout * 1000);
+    } else if (!isAdmin && readonly_timeout > 0) {
+      this.set('userTimeOut', readonly_timeout * 1000);
+    }
+    if (this.get('userTimeOut') > 0) {
+      this.startMonitorInactivity();
+    }
+  },
+
+  startMonitorInactivity: function() {
+    this.set('isUserActive', true);
+    this.set('lastUserActiveTime', Date.now());
+
+    this.rebindActivityEventMonitors();
+    if (!this.get('checkActivenessInterval')) {
+      this.set('checkActivenessInterval', window.setInterval(this.checkActiveness, 1000));
+    }
+  },
+
+  /* this will be triggerred by user driven events: 'mousemove', 'keypress' and 'click' */
+  keepActive: function() {
+    var scope = App.router.get('mainController');
+    //console.error('keepActive');
+    if (scope.get('isUserActive')) {
+      scope.set('lastUserActiveTime', Date.now());
+    }
+  },
+
+  checkActiveness: function() {
+    var scope = App.router.get('mainController');
+    //console.error("checkActiveness " + scope.get('lastUserActiveTime') + " : " + Date.now());
+    if (Date.now() - scope.get('lastUserActiveTime') > scope.get('userTimeOut')) {
+      scope.set('isUserActive', false);
+      //console.error("LOGOUT!");
+      scope.unbindActivityEventMonitors();
+      clearInterval(scope.get('checkActivenessInterval'));
+      App.router.logOff({});
+    }
+  },
 
+  rebindActivityEventMonitors: function() {
+    this.unbindActivityEventMonitors();
+    this.bindActivityEventMonitors();
+  },
+
+  bindActivityEventMonitors: function() {
+    $(window).bind('mousemove', this.keepActive);
+    $(window).bind('keypress', this.keepActive);
+    $(window).bind('click', this.keepActive);
+    // iframes need to be monitored as well
+    var iframes = $('iframe');
+    if (iframes.length > 0) {
+      for (var i = 0; i < iframes.length; i++) {
+        var iframe = iframes[i];
+        $(iframe.contentWindow).bind('mousemove', this.keepActive);
+        $(iframe.contentWindow).bind('keypress', this.keepActive);
+        $(iframe.contentWindow).bind('click', this.keepActive);
+      }
+    }
+  },
+
+  unbindActivityEventMonitors: function() {
+    $(window).unbind('mousemove', this.keepActive);
+    $(window).unbind('keypress', this.keepActive);
+    $(window).unbind('click', this.keepActive);
+    // iframes need to be monitored as well
+    var iframes = $('iframe');
+    if (iframes.length > 0) {
+      for (var i = 0; i < iframes.length; i++) {
+        var iframe = iframes[i];
+        $(iframe.contentWindow).unbind('mousemove', this.keepActive);
+        $(iframe.contentWindow).unbind('keypress', this.keepActive);
+        $(iframe.contentWindow).unbind('click', this.keepActive);
+      }
+    }
+  }
 });

+ 1 - 0
ambari-web/app/views/main/views/details.js

@@ -49,6 +49,7 @@ App.MainViewsDetailsView = Em.View.extend({
     }, 5000);
     self.set('interval', interval);
     this.resizeFunction();
+    App.router.get('mainController').monitorInactivity();
   },
 
   resizeFunction : function() {