You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ni...@apache.org on 2021/08/31 15:25:44 UTC

[atlas] branch master updated (097f50e -> 5deac62)

This is an automated email from the ASF dual-hosted git repository.

nixon pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git.


    from 097f50e  ATLAS-4403: Improve find entity by unique attributes logic - when multiple unique attributes exist for entity type
     new fbbefce  ATLAS-4379 : Atlas Filter changes for user inactivity on Atlas UI
     new 5deac62  ATLAS-4378: UI - Implement session timeout on Atlas UI.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 dashboardv2/public/css/scss/override.scss          |   6 +
 .../js/external_lib/idealTimeout/store.min.js      |   2 +
 dashboardv2/public/js/main.js                      |  27 +-
 dashboardv2/public/js/utils/Globals.js             |   1 +
 dashboardv2/public/js/utils/Utils.js               | 271 ++++++++++++++++++++-
 dashboardv3/public/css/scss/override.scss          |   6 +
 .../js/external_lib/idealTimeout/store.min.js      |   2 +
 dashboardv3/public/js/main.js                      |  27 +-
 dashboardv3/public/js/utils/Globals.js             |   1 +
 dashboardv3/public/js/utils/Utils.js               | 267 +++++++++++++++++++-
 .../java/org/apache/atlas/AtlasConfiguration.java  |   4 +-
 .../web/filters/AtlasAuthenticationFilter.java     |  48 +++-
 .../org/apache/atlas/web/filters/RestUtil.java     | 108 ++++++++
 .../apache/atlas/web/resources/AdminResource.java  |   1 +
 .../AtlasAuthenticationSuccessHandler.java         |  16 +-
 15 files changed, 774 insertions(+), 13 deletions(-)
 create mode 100644 dashboardv2/public/js/external_lib/idealTimeout/store.min.js
 create mode 100644 dashboardv3/public/js/external_lib/idealTimeout/store.min.js
 create mode 100644 webapp/src/main/java/org/apache/atlas/web/filters/RestUtil.java

[atlas] 02/02: ATLAS-4378: UI - Implement session timeout on Atlas UI.

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

nixon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git

commit 5deac6277cb5e0676e811f682da2a7692a9f628e
Author: prasad pawar <pr...@freestoneinfotech.com>
AuthorDate: Thu Aug 26 18:59:12 2021 +0530

    ATLAS-4378: UI - Implement session timeout on Atlas UI.
---
 dashboardv2/public/css/scss/override.scss          |   6 +
 .../js/external_lib/idealTimeout/store.min.js      |   2 +
 dashboardv2/public/js/main.js                      |  27 +-
 dashboardv2/public/js/utils/Globals.js             |   1 +
 dashboardv2/public/js/utils/Utils.js               | 271 ++++++++++++++++++++-
 dashboardv3/public/css/scss/override.scss          |   6 +
 .../js/external_lib/idealTimeout/store.min.js      |   2 +
 dashboardv3/public/js/main.js                      |  27 +-
 dashboardv3/public/js/utils/Globals.js             |   1 +
 dashboardv3/public/js/utils/Utils.js               | 267 +++++++++++++++++++-
 10 files changed, 604 insertions(+), 6 deletions(-)

diff --git a/dashboardv2/public/css/scss/override.scss b/dashboardv2/public/css/scss/override.scss
index c24b0c6..549ae3b 100644
--- a/dashboardv2/public/css/scss/override.scss
+++ b/dashboardv2/public/css/scss/override.scss
@@ -575,4 +575,10 @@ div.columnmanager-dropdown-container {
     ul {
         list-style: disc;
     }
+}
+
+.ideal-timeout {
+    .modal-content {
+        border-radius: 0px !important;
+    }
 }
\ No newline at end of file
diff --git a/dashboardv2/public/js/external_lib/idealTimeout/store.min.js b/dashboardv2/public/js/external_lib/idealTimeout/store.min.js
new file mode 100644
index 0000000..7334a7e
--- /dev/null
+++ b/dashboardv2/public/js/external_lib/idealTimeout/store.min.js
@@ -0,0 +1,2 @@
+/* Copyright (c) 2010-2013 Marcus Westin */
+"use strict";(function(e,t){typeof define=="function"&&define.amd?define([],t):typeof exports=="object"?module.exports=t():e.store=t()})(this,function(){function o(){try{return r in t&&t[r]}catch(e){return!1}}var e={},t=window,n=t.document,r="localStorage",i="script",s;e.disabled=!1,e.version="1.3.17",e.set=function(e,t){},e.get=function(e,t){},e.has=function(t){return e.get(t)!==undefined},e.remove=function(e){},e.clear=function(){},e.transact=function(t,n,r){r==null&&(r=n,n=null),n==nu [...]
\ No newline at end of file
diff --git a/dashboardv2/public/js/main.js b/dashboardv2/public/js/main.js
index 7c8bbb4..f2ea1d8 100644
--- a/dashboardv2/public/js/main.js
+++ b/dashboardv2/public/js/main.js
@@ -178,7 +178,8 @@ require.config({
         'jstree': 'libs/jstree/jstree.min',
         'jquery-steps': 'libs/jquery-steps/jquery.steps.min',
         'dropzone': 'libs/dropzone/js/dropzone-amd-module',
-        'lossless-json': 'libs/lossless-json/lossless-json'
+        'lossless-json': 'libs/lossless-json/lossless-json',
+        'store': 'external_lib/idealTimeout/store.min'
     },
 
     /**
@@ -199,11 +200,12 @@ require(['App',
     'collection/VEntityList',
     'collection/VTagList',
     'utils/Enums',
+    'utils/Utils',
     'utils/Overrides',
     'bootstrap',
     'd3',
     'select2'
-], function(App, Router, Helper, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList, Enums) {
+], function(App, Router, Helper, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList, Enums, Utils) {
     var that = this;
     this.asyncFetchCounter = 5 + (Enums.addOnEntities.length + 1);
     // entity
@@ -286,6 +288,27 @@ require(['App',
                 if (response['atlas.tasks.enabled'] !== undefined) {
                     Globals.isTasksEnabled = response['atlas.tasks.enabled'];
                 }
+                if (response['atlas.session.timeout.secs']) { Globals.idealTimeoutSeconds = response['atlas.session.timeout.secs']; }
+                /*  Atlas idealTimeout 
+       redirectUrl: url to redirect after timeout
+       idealTimeLimit: timeout in seconds
+       activityEvents: ideal keyboard mouse events
+       dialogDisplayLimit: show popup before timeout in seconds
+       */
+                $(document).ready(function() {
+                    $(document).idleTimeout({
+                        redirectUrl: Utils.getBaseUrl(window.location.pathname) + '/index.html?action=timeout', // redirect to this url
+                        idleTimeLimit: Globals.idealTimeoutSeconds, // 900 seconds
+                        activityEvents: 'click keypress scroll wheel mousemove', // separate each event with a space
+                        dialogDisplayLimit: 10, // Time to display the warning dialog before logout (and optional callback) in seconds
+                        sessionKeepAliveTimer: false, // Set to false to disable pings.
+                        onModalKeepAlive: function() {
+                            CommonViewFunction.userDataFetch({
+                                url: UrlLinks.sessionApiUrl()
+                            })
+                        }
+                    });
+                });
             }
             --that.asyncFetchCounter;
             startApp();
diff --git a/dashboardv2/public/js/utils/Globals.js b/dashboardv2/public/js/utils/Globals.js
index b0dc5cd..8fe8ebc 100644
--- a/dashboardv2/public/js/utils/Globals.js
+++ b/dashboardv2/public/js/utils/Globals.js
@@ -49,6 +49,7 @@ define(["require"], function(require) {
 
     Globals.isDebugMetricsEnabled = false;
     Globals.isTasksEnabled = false;
+    Globals.idealTimeoutSeconds = 900;
 
     return Globals;
 });
\ No newline at end of file
diff --git a/dashboardv2/public/js/utils/Utils.js b/dashboardv2/public/js/utils/Utils.js
index f426b6c..f2498d8 100644
--- a/dashboardv2/public/js/utils/Utils.js
+++ b/dashboardv2/public/js/utils/Utils.js
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums', 'moment', 'moment-timezone', 'pnotify.buttons', 'pnotify.confirm'], function(require, Globals, pnotify, Messages, Enums, moment) {
+define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums', 'moment', 'store', 'modules/Modal', 'moment-timezone', 'pnotify.buttons', 'pnotify.confirm'], function(require, Globals, pnotify, Messages, Enums, moment, store, Modal) {
     'use strict';
 
     var Utils = {};
@@ -952,5 +952,274 @@ define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums',
         }
         return dateValue;
     }
+    //------------------------------------------------idleTimeout-----------------------------
+    $.fn.idleTimeout = function(userRuntimeConfig) {
+
+        //##############################
+        //## Public Configuration Variables
+        //##############################
+        var defaultConfig = {
+                redirectUrl: Utils.getBaseUrl(window.location.pathname) + '/index.html?action=timeout', // redirect to this url on logout. Set to "redirectUrl: false" to disable redirect
+
+                // idle settings
+                idleTimeLimit: Globals.idealTimeoutSeconds, // 'No activity' time limit in seconds. 1200 = 20 Minutes
+                idleCheckHeartbeat: 2, // Frequency to check for idle timeouts in seconds
+
+                // optional custom callback to perform before logout
+                customCallback: false, // set to false for no customCallback
+                // customCallback:    function () {    // define optional custom js function
+                // perform custom action before logout
+                // },
+
+                // configure which activity events to detect
+                // http://www.quirksmode.org/dom/events/
+                // https://developer.mozilla.org/en-US/docs/Web/Reference/Events
+                activityEvents: 'click keypress scroll wheel mousewheel mousemove', // separate each event with a space
+
+                // warning dialog box configuration
+                enableDialog: true, // set to false for logout without warning dialog
+                dialogDisplayLimit: 10, // Time to display the warning dialog before logout (and optional callback) in seconds. 180 = 3 Minutes
+                dialogTitle: 'Your session is about to expire!', // also displays on browser title bar
+                dialogText: 'Your session is about to expire.',
+                dialogTimeRemaining: 'You will be logged out in ',
+                dialogStayLoggedInButton: 'Stay Logged In',
+                dialogLogOutNowButton: 'Logout',
+
+                // error message if https://github.com/marcuswestin/store.js not enabled
+                errorAlertMessage: 'Please disable "Private Mode", or upgrade to a modern browser. Or perhaps a dependent file missing. Please see: https://github.com/marcuswestin/store.js',
+
+                // server-side session keep-alive timer
+                sessionKeepAliveTimer: 600, // ping the server at this interval in seconds. 600 = 10 Minutes. Set to false to disable pings
+                sessionKeepAliveUrl: window.location.href // set URL to ping - does not apply if sessionKeepAliveTimer: false
+            },
+
+            //##############################
+            //## Private Variables
+            //##############################
+            currentConfig = $.extend(defaultConfig, userRuntimeConfig), // merge default and user runtime configuration
+            origTitle = document.title, // save original browser title
+            activityDetector,
+            startKeepSessionAlive, stopKeepSessionAlive, keepSession, keepAlivePing, // session keep alive
+            idleTimer, remainingTimer, checkIdleTimeout, checkIdleTimeoutLoop, startIdleTimer, stopIdleTimer, // idle timer
+            openWarningDialog, dialogTimer, checkDialogTimeout, startDialogTimer, stopDialogTimer, isDialogOpen, destroyWarningDialog, countdownDisplay, // warning dialog
+            logoutUser;
+
+        //##############################
+        //## Public Functions
+        //##############################
+        // trigger a manual user logout
+        // use this code snippet on your site's Logout button: $.fn.idleTimeout().logout();
+        this.logout = function() {
+            store.set('idleTimerLoggedOut', true);
+        };
+
+        //##############################
+        //## Private Functions
+        //##############################
+
+        //----------- KEEP SESSION ALIVE FUNCTIONS --------------//
+        startKeepSessionAlive = function() {
+
+            keepSession = function() {
+                $.get(currentConfig.sessionKeepAliveUrl);
+                startKeepSessionAlive();
+            };
+
+            keepAlivePing = setTimeout(keepSession, (currentConfig.sessionKeepAliveTimer * 1000));
+        };
+
+        stopKeepSessionAlive = function() {
+            clearTimeout(keepAlivePing);
+        };
+
+        //----------- ACTIVITY DETECTION FUNCTION --------------//
+        activityDetector = function() {
+
+            $('body').on(currentConfig.activityEvents, function() {
+
+                if (!currentConfig.enableDialog || (currentConfig.enableDialog && isDialogOpen() !== true)) {
+                    startIdleTimer();
+                    $('#activity').effect('shake'); // added for demonstration page
+                }
+            });
+        };
+
+        //----------- IDLE TIMER FUNCTIONS --------------//
+        checkIdleTimeout = function() {
+
+            var timeIdleTimeout = (store.get('idleTimerLastActivity') + (currentConfig.idleTimeLimit * 1000));
+
+            if ($.now() > timeIdleTimeout) {
+
+                if (!currentConfig.enableDialog) { // warning dialog is disabled
+                    logoutUser(); // immediately log out user when user is idle for idleTimeLimit
+                } else if (currentConfig.enableDialog && isDialogOpen() !== true) {
+                    openWarningDialog();
+                    startDialogTimer(); // start timing the warning dialog
+                }
+            } else if (store.get('idleTimerLoggedOut') === true) { //a 'manual' user logout?
+                logoutUser();
+            } else {
+
+                if (currentConfig.enableDialog && isDialogOpen() === true) {
+                    destroyWarningDialog();
+                    stopDialogTimer();
+                }
+            }
+        };
+
+        startIdleTimer = function() {
+            stopIdleTimer();
+            store.set('idleTimerLastActivity', $.now());
+            checkIdleTimeoutLoop();
+        };
+
+        checkIdleTimeoutLoop = function() {
+            checkIdleTimeout();
+            idleTimer = setTimeout(checkIdleTimeoutLoop, (currentConfig.idleCheckHeartbeat * 1000));
+        };
+
+        stopIdleTimer = function() {
+            clearTimeout(idleTimer);
+        };
+
+        //----------- WARNING DIALOG FUNCTIONS --------------//
+        openWarningDialog = function() {
+
+
+            var dialogContent = "<div id='idletimer_warning_dialog'><p>" + currentConfig.dialogText + "</p><p style='display:inline'>" + currentConfig.dialogTimeRemaining + ": <div style='display:inline' id='countdownDisplay'></div> secs.</p></div>";
+
+            var that = this,
+                modalObj = {
+                    title: currentConfig.dialogTitle,
+                    htmlContent: dialogContent,
+                    okText: "Stay Signed-in",
+                    cancelText: 'Logout',
+                    mainClass: 'modal-lg',
+                    allowCancel: true,
+                    okCloses: false,
+                    escape: false,
+                    cancellable: true,
+                    width: "500px",
+                    mainClass: "ideal-timeout"
+                };
+            var modal = new Modal(modalObj);
+            modal.open();
+            modal.on('ok', function() {
+                if (userRuntimeConfig && userRuntimeConfig.onModalKeepAlive) {
+                    userRuntimeConfig.onModalKeepAlive(); //hit session API
+                }
+                destroyWarningDialog();
+                modal.close();
+                stopDialogTimer();
+                startIdleTimer();
+                CommonViewFunction.userDataFetch({
+                    url: UrlLinks.sessionApiUrl()
+                })
+
+            });
+            modal.on('closeModal', function() {
+                logoutUser();
+            });
+
+            countdownDisplay();
+
+            // document.title = currentConfig.dialogTitle;
+
+            if (currentConfig.sessionKeepAliveTimer) {
+                stopKeepSessionAlive();
+            }
+        };
+
+        checkDialogTimeout = function() {
+            var timeDialogTimeout = (store.get('idleTimerLastActivity') + (currentConfig.idleTimeLimit * 1000) + (currentConfig.dialogDisplayLimit * 1000));
+
+            if (($.now() > timeDialogTimeout) || (store.get('idleTimerLoggedOut') === true)) {
+                logoutUser();
+            }
+        };
+
+        startDialogTimer = function() {
+            dialogTimer = setInterval(checkDialogTimeout, (currentConfig.idleCheckHeartbeat * 1000));
+        };
+
+        stopDialogTimer = function() {
+            clearInterval(dialogTimer);
+            clearInterval(remainingTimer);
+        };
+
+        isDialogOpen = function() {
+            var dialogOpen = $("#idletimer_warning_dialog").is(":visible");
+
+            if (dialogOpen === true) {
+                return true;
+            }
+            return false;
+        };
+
+        destroyWarningDialog = function() {
+            if (currentConfig.sessionKeepAliveTimer) {
+                startKeepSessionAlive();
+            }
+        };
+
+        countdownDisplay = function() {
+            var dialogDisplaySeconds = currentConfig.dialogDisplayLimit,
+                mins, secs;
+
+            remainingTimer = setInterval(function() {
+                mins = Math.floor(dialogDisplaySeconds / 60); // minutes
+                if (mins < 10) { mins = '0' + mins; }
+                secs = dialogDisplaySeconds - (mins * 60); // seconds
+                if (secs < 10) { secs = '0' + secs; }
+                $('#countdownDisplay').html(mins + ':' + secs);
+                dialogDisplaySeconds -= 1;
+            }, 1000);
+        };
+
+        //----------- LOGOUT USER FUNCTION --------------//
+        logoutUser = function() {
+            store.set('idleTimerLoggedOut', true);
+
+            if (currentConfig.sessionKeepAliveTimer) {
+                stopKeepSessionAlive();
+            }
+
+            if (currentConfig.customCallback) {
+                currentConfig.customCallback();
+            }
+
+            if (currentConfig.redirectUrl) {
+                window.location.href = currentConfig.redirectUrl;
+            }
+        };
+
+        //###############################
+        // Build & Return the instance of the item as a plugin
+        // This is your construct.
+        //###############################
+        return this.each(function() {
+
+            if (store.enabled) {
+
+                store.set('idleTimerLastActivity', $.now());
+                store.set('idleTimerLoggedOut', false);
+
+                activityDetector();
+
+                if (currentConfig.sessionKeepAliveTimer) {
+                    startKeepSessionAlive();
+                }
+
+                startIdleTimer();
+
+            } else {
+                alert(currentConfig.errorAlertMessage);
+            }
+
+        });
+    };
+
+    //------------------------------------------------
     return Utils;
 });
\ No newline at end of file
diff --git a/dashboardv3/public/css/scss/override.scss b/dashboardv3/public/css/scss/override.scss
index c1841eb..2c3ea78 100644
--- a/dashboardv3/public/css/scss/override.scss
+++ b/dashboardv3/public/css/scss/override.scss
@@ -577,4 +577,10 @@ div.columnmanager-dropdown-container {
     ul {
         list-style: disc;
     }
+}
+
+.ideal-timeout {
+    .modal-content {
+        border-radius: 0px !important;
+    }
 }
\ No newline at end of file
diff --git a/dashboardv3/public/js/external_lib/idealTimeout/store.min.js b/dashboardv3/public/js/external_lib/idealTimeout/store.min.js
new file mode 100644
index 0000000..7334a7e
--- /dev/null
+++ b/dashboardv3/public/js/external_lib/idealTimeout/store.min.js
@@ -0,0 +1,2 @@
+/* Copyright (c) 2010-2013 Marcus Westin */
+"use strict";(function(e,t){typeof define=="function"&&define.amd?define([],t):typeof exports=="object"?module.exports=t():e.store=t()})(this,function(){function o(){try{return r in t&&t[r]}catch(e){return!1}}var e={},t=window,n=t.document,r="localStorage",i="script",s;e.disabled=!1,e.version="1.3.17",e.set=function(e,t){},e.get=function(e,t){},e.has=function(t){return e.get(t)!==undefined},e.remove=function(e){},e.clear=function(){},e.transact=function(t,n,r){r==null&&(r=n,n=null),n==nu [...]
\ No newline at end of file
diff --git a/dashboardv3/public/js/main.js b/dashboardv3/public/js/main.js
index 374641e..97e177c 100644
--- a/dashboardv3/public/js/main.js
+++ b/dashboardv3/public/js/main.js
@@ -207,7 +207,8 @@ require.config({
         'jstree': 'libs/jstree/jstree.min',
         'jquery-steps': 'libs/jquery-steps/jquery.steps.min',
         'dropzone': 'libs/dropzone/js/dropzone-amd-module',
-        'lossless-json': 'libs/lossless-json/lossless-json'
+        'lossless-json': 'libs/lossless-json/lossless-json',
+        'store': 'external_lib/idealTimeout/store.min'
     },
 
     /**
@@ -228,11 +229,12 @@ require(['App',
     'collection/VEntityList',
     'collection/VTagList',
     'utils/Enums',
+    'utils/Utils',
     'utils/Overrides',
     'bootstrap',
     'd3',
     'select2'
-], function(App, Router, Helper, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList, Enums) {
+], function(App, Router, Helper, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList, Enums, Utils) {
     var that = this;
     this.asyncFetchCounter = 5 + (Enums.addOnEntities.length + 1);
     // entity
@@ -315,6 +317,27 @@ require(['App',
                 if (response['atlas.tasks.enabled'] !== undefined) {
                     Globals.isTasksEnabled = response['atlas.tasks.enabled'];
                 }
+                if (response['atlas.session.timeout.secs']) { Globals.idealTimeoutSeconds = response['atlas.session.timeout.secs']; }
+                /*  Atlas idealTimeout 
+       redirectUrl: url to redirect after timeout
+       idealTimeLimit: timeout in seconds
+       activityEvents: ideal keyboard mouse events
+       dialogDisplayLimit: show popup before timeout in seconds
+       */
+                $(document).ready(function() {
+                    $(document).idleTimeout({
+                        redirectUrl: Utils.getBaseUrl(window.location.pathname) + '/index.html?action=timeout', // redirect to this url
+                        idleTimeLimit: Globals.idealTimeoutSeconds, // 900 seconds
+                        activityEvents: 'click keypress scroll wheel mousemove', // separate each event with a space
+                        dialogDisplayLimit: 10, // Time to display the warning dialog before logout (and optional callback) in seconds
+                        sessionKeepAliveTimer: false, // Set to false to disable pings.
+                        onModalKeepAlive: function() {
+                            CommonViewFunction.userDataFetch({
+                                url: UrlLinks.sessionApiUrl()
+                            })
+                        }
+                    });
+                });
             }
             --that.asyncFetchCounter;
             startApp();
diff --git a/dashboardv3/public/js/utils/Globals.js b/dashboardv3/public/js/utils/Globals.js
index b0dc5cd..8fe8ebc 100644
--- a/dashboardv3/public/js/utils/Globals.js
+++ b/dashboardv3/public/js/utils/Globals.js
@@ -49,6 +49,7 @@ define(["require"], function(require) {
 
     Globals.isDebugMetricsEnabled = false;
     Globals.isTasksEnabled = false;
+    Globals.idealTimeoutSeconds = 900;
 
     return Globals;
 });
\ No newline at end of file
diff --git a/dashboardv3/public/js/utils/Utils.js b/dashboardv3/public/js/utils/Utils.js
index 1a73b7c..c3122fc 100644
--- a/dashboardv3/public/js/utils/Utils.js
+++ b/dashboardv3/public/js/utils/Utils.js
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums', 'moment', 'moment-timezone', 'pnotify.buttons', 'pnotify.confirm'], function(require, Globals, pnotify, Messages, Enums, moment) {
+define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums', 'moment', 'store', 'modules/Modal', 'moment-timezone', 'pnotify.buttons', 'pnotify.confirm'], function(require, Globals, pnotify, Messages, Enums, moment, store, Modal) {
     'use strict';
 
     var Utils = {};
@@ -964,5 +964,270 @@ define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums',
         }
         return dateValue;
     }
+    //------------------------------------------------idleTimeout-----------------------------
+    $.fn.idleTimeout = function(userRuntimeConfig) {
+
+        //##############################
+        //## Public Configuration Variables
+        //##############################
+        var defaultConfig = {
+                redirectUrl: Utils.getBaseUrl(window.location.pathname) + '/index.html?action=timeout', // redirect to this url on logout. Set to "redirectUrl: false" to disable redirect
+
+                // idle settings
+                idleTimeLimit: Globals.idealTimeoutSeconds, // 'No activity' time limit in seconds. 1200 = 20 Minutes
+                idleCheckHeartbeat: 2, // Frequency to check for idle timeouts in seconds
+
+                // optional custom callback to perform before logout
+                customCallback: false, // set to false for no customCallback
+                // customCallback:    function () {    // define optional custom js function
+                // perform custom action before logout
+                // },
+
+                // configure which activity events to detect
+                // http://www.quirksmode.org/dom/events/
+                // https://developer.mozilla.org/en-US/docs/Web/Reference/Events
+                activityEvents: 'click keypress scroll wheel mousewheel mousemove', // separate each event with a space
+
+                // warning dialog box configuration
+                enableDialog: true, // set to false for logout without warning dialog
+                dialogDisplayLimit: 10, // Time to display the warning dialog before logout (and optional callback) in seconds. 180 = 3 Minutes
+                dialogTitle: 'Your session is about to expire!', // also displays on browser title bar
+                dialogText: 'Your session is about to expire.',
+                dialogTimeRemaining: 'You will be logged out in ',
+                dialogStayLoggedInButton: 'Stay Logged In',
+                dialogLogOutNowButton: 'Logout',
+
+                // error message if https://github.com/marcuswestin/store.js not enabled
+                errorAlertMessage: 'Please disable "Private Mode", or upgrade to a modern browser. Or perhaps a dependent file missing. Please see: https://github.com/marcuswestin/store.js',
+
+                // server-side session keep-alive timer
+                sessionKeepAliveTimer: 600, // ping the server at this interval in seconds. 600 = 10 Minutes. Set to false to disable pings
+                sessionKeepAliveUrl: window.location.href // set URL to ping - does not apply if sessionKeepAliveTimer: false
+            },
+
+            //##############################
+            //## Private Variables
+            //##############################
+            currentConfig = $.extend(defaultConfig, userRuntimeConfig), // merge default and user runtime configuration
+            origTitle = document.title, // save original browser title
+            activityDetector,
+            startKeepSessionAlive, stopKeepSessionAlive, keepSession, keepAlivePing, // session keep alive
+            idleTimer, remainingTimer, checkIdleTimeout, checkIdleTimeoutLoop, startIdleTimer, stopIdleTimer, // idle timer
+            openWarningDialog, dialogTimer, checkDialogTimeout, startDialogTimer, stopDialogTimer, isDialogOpen, destroyWarningDialog, countdownDisplay, // warning dialog
+            logoutUser;
+
+        //##############################
+        //## Public Functions
+        //##############################
+        // trigger a manual user logout
+        // use this code snippet on your site's Logout button: $.fn.idleTimeout().logout();
+        this.logout = function() {
+            store.set('idleTimerLoggedOut', true);
+        };
+
+        //##############################
+        //## Private Functions
+        //##############################
+
+        //----------- KEEP SESSION ALIVE FUNCTIONS --------------//
+        startKeepSessionAlive = function() {
+
+            keepSession = function() {
+                $.get(currentConfig.sessionKeepAliveUrl);
+                startKeepSessionAlive();
+            };
+
+            keepAlivePing = setTimeout(keepSession, (currentConfig.sessionKeepAliveTimer * 1000));
+        };
+
+        stopKeepSessionAlive = function() {
+            clearTimeout(keepAlivePing);
+        };
+
+        //----------- ACTIVITY DETECTION FUNCTION --------------//
+        activityDetector = function() {
+
+            $('body').on(currentConfig.activityEvents, function() {
+
+                if (!currentConfig.enableDialog || (currentConfig.enableDialog && isDialogOpen() !== true)) {
+                    startIdleTimer();
+                    $('#activity').effect('shake'); // added for demonstration page
+                }
+            });
+        };
+
+        //----------- IDLE TIMER FUNCTIONS --------------//
+        checkIdleTimeout = function() {
+
+            var timeIdleTimeout = (store.get('idleTimerLastActivity') + (currentConfig.idleTimeLimit * 1000));
+
+            if ($.now() > timeIdleTimeout) {
+
+                if (!currentConfig.enableDialog) { // warning dialog is disabled
+                    logoutUser(); // immediately log out user when user is idle for idleTimeLimit
+                } else if (currentConfig.enableDialog && isDialogOpen() !== true) {
+                    openWarningDialog();
+                    startDialogTimer(); // start timing the warning dialog
+                }
+            } else if (store.get('idleTimerLoggedOut') === true) { //a 'manual' user logout?
+                logoutUser();
+            } else {
+
+                if (currentConfig.enableDialog && isDialogOpen() === true) {
+                    destroyWarningDialog();
+                    stopDialogTimer();
+                }
+            }
+        };
+
+        startIdleTimer = function() {
+            stopIdleTimer();
+            store.set('idleTimerLastActivity', $.now());
+            checkIdleTimeoutLoop();
+        };
+
+        checkIdleTimeoutLoop = function() {
+            checkIdleTimeout();
+            idleTimer = setTimeout(checkIdleTimeoutLoop, (currentConfig.idleCheckHeartbeat * 1000));
+        };
+
+        stopIdleTimer = function() {
+            clearTimeout(idleTimer);
+        };
+
+        //----------- WARNING DIALOG FUNCTIONS --------------//
+        openWarningDialog = function() {
+
+
+            var dialogContent = "<div id='idletimer_warning_dialog'><p>" + currentConfig.dialogText + "</p><p style='display:inline'>" + currentConfig.dialogTimeRemaining + ": <div style='display:inline' id='countdownDisplay'></div> secs.</p></div>";
+
+            var that = this,
+                modalObj = {
+                    title: currentConfig.dialogTitle,
+                    htmlContent: dialogContent,
+                    okText: "Stay Signed-in",
+                    cancelText: 'Logout',
+                    mainClass: 'modal-lg',
+                    allowCancel: true,
+                    okCloses: false,
+                    escape: false,
+                    cancellable: true,
+                    width: "500px",
+                    mainClass: "ideal-timeout"
+                };
+            var modal = new Modal(modalObj);
+            modal.open();
+            modal.on('ok', function() {
+                if (userRuntimeConfig && userRuntimeConfig.onModalKeepAlive) {
+                    userRuntimeConfig.onModalKeepAlive(); //hit session API
+                }
+                destroyWarningDialog();
+                modal.close();
+                stopDialogTimer();
+                startIdleTimer();
+            });
+            modal.on('closeModal', function() {
+                logoutUser();
+            });
+
+            countdownDisplay();
+
+            // document.title = currentConfig.dialogTitle;
+
+            if (currentConfig.sessionKeepAliveTimer) {
+                stopKeepSessionAlive();
+            }
+        };
+
+        checkDialogTimeout = function() {
+            var timeDialogTimeout = (store.get('idleTimerLastActivity') + (currentConfig.idleTimeLimit * 1000) + (currentConfig.dialogDisplayLimit * 1000));
+
+            if (($.now() > timeDialogTimeout) || (store.get('idleTimerLoggedOut') === true)) {
+                logoutUser();
+            }
+        };
+
+        startDialogTimer = function() {
+            dialogTimer = setInterval(checkDialogTimeout, (currentConfig.idleCheckHeartbeat * 1000));
+        };
+
+        stopDialogTimer = function() {
+            clearInterval(dialogTimer);
+            clearInterval(remainingTimer);
+        };
+
+        isDialogOpen = function() {
+            var dialogOpen = $("#idletimer_warning_dialog").is(":visible");
+
+            if (dialogOpen === true) {
+                return true;
+            }
+            return false;
+        };
+
+        destroyWarningDialog = function() {
+            if (currentConfig.sessionKeepAliveTimer) {
+                startKeepSessionAlive();
+            }
+        };
+
+        countdownDisplay = function() {
+            var dialogDisplaySeconds = currentConfig.dialogDisplayLimit,
+                mins, secs;
+
+            remainingTimer = setInterval(function() {
+                mins = Math.floor(dialogDisplaySeconds / 60); // minutes
+                if (mins < 10) { mins = '0' + mins; }
+                secs = dialogDisplaySeconds - (mins * 60); // seconds
+                if (secs < 10) { secs = '0' + secs; }
+                $('#countdownDisplay').html(mins + ':' + secs);
+                dialogDisplaySeconds -= 1;
+            }, 1000);
+        };
+
+        //----------- LOGOUT USER FUNCTION --------------//
+        logoutUser = function() {
+            store.set('idleTimerLoggedOut', true);
+
+            if (currentConfig.sessionKeepAliveTimer) {
+                stopKeepSessionAlive();
+            }
+
+            if (currentConfig.customCallback) {
+                currentConfig.customCallback();
+            }
+
+            if (currentConfig.redirectUrl) {
+                window.location.href = currentConfig.redirectUrl;
+            }
+        };
+
+        //###############################
+        // Build & Return the instance of the item as a plugin
+        // This is your construct.
+        //###############################
+        return this.each(function() {
+
+            if (store.enabled) {
+
+                store.set('idleTimerLastActivity', $.now());
+                store.set('idleTimerLoggedOut', false);
+
+                activityDetector();
+
+                if (currentConfig.sessionKeepAliveTimer) {
+                    startKeepSessionAlive();
+                }
+
+                startIdleTimer();
+
+            } else {
+                alert(currentConfig.errorAlertMessage);
+            }
+
+        });
+    };
+
+    //------------------------------------------------
     return Utils;
 });
\ No newline at end of file

[atlas] 01/02: ATLAS-4379 : Atlas Filter changes for user inactivity on Atlas UI

Posted by ni...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

nixon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git

commit fbbefce84eaa0e846faa01eb79b79a8f3184348f
Author: nixonrodrigues <ni...@apache.org>
AuthorDate: Mon Aug 23 17:27:18 2021 +0530

    ATLAS-4379 : Atlas Filter changes for user inactivity on Atlas UI
---
 .../java/org/apache/atlas/AtlasConfiguration.java  |   4 +-
 .../web/filters/AtlasAuthenticationFilter.java     |  48 ++++++++-
 .../org/apache/atlas/web/filters/RestUtil.java     | 108 +++++++++++++++++++++
 .../apache/atlas/web/resources/AdminResource.java  |   1 +
 .../AtlasAuthenticationSuccessHandler.java         |  16 ++-
 5 files changed, 170 insertions(+), 7 deletions(-)

diff --git a/intg/src/main/java/org/apache/atlas/AtlasConfiguration.java b/intg/src/main/java/org/apache/atlas/AtlasConfiguration.java
index 2f2c8a5..fa519ef 100644
--- a/intg/src/main/java/org/apache/atlas/AtlasConfiguration.java
+++ b/intg/src/main/java/org/apache/atlas/AtlasConfiguration.java
@@ -80,7 +80,9 @@ public enum AtlasConfiguration {
     DSL_EXECUTOR_TRAVERSAL("atlas.dsl.executor.traversal", true),
     DSL_CACHED_TRANSLATOR("atlas.dsl.cached.translator", true),
     DEBUG_METRICS_ENABLED("atlas.debug.metrics.enabled", false),
-    TASKS_USE_ENABLED("atlas.tasks.enabled", true);
+    TASKS_USE_ENABLED("atlas.tasks.enabled", true),
+    SESSION_TIMEOUT_SECS("atlas.session.timeout.secs", 3600);
+
 
     private static final Configuration APPLICATION_PROPERTIES;
 
diff --git a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
index d9b1c82..b8d21b9 100644
--- a/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
+++ b/webapp/src/main/java/org/apache/atlas/web/filters/AtlasAuthenticationFilter.java
@@ -19,6 +19,7 @@
 package org.apache.atlas.web.filters;
 
 import org.apache.atlas.ApplicationProperties;
+import org.apache.atlas.AtlasConfiguration;
 import org.apache.atlas.security.SecurityProperties;
 import org.apache.atlas.utils.AuthenticationUtil;
 import org.apache.atlas.web.security.AtlasAuthenticationProvider;
@@ -73,6 +74,9 @@ import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.apache.hadoop.security.authorize.AuthorizationException;
+import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
+
+import static org.apache.atlas.web.filters.RestUtil.constructForwardableURL;
 
 
 /**
@@ -90,6 +94,7 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
     private   static final String[]       DEFAULT_PROXY_USERS   = new String[] { "knox" };
     private   static final String         CONF_PROXYUSER_PREFIX = "atlas.proxyuser";
     protected static final ServletContext nullContext           = new NullServletContext();
+    private   static final String         ORIGINAL_URL_QUERY_PARAM = "originalUrl";
 
     private Signer               signer;
     private SignerSecretProvider secretProvider;
@@ -102,8 +107,9 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
     private Set<String>          atlasProxyUsers = new HashSet<>();
     private HttpServlet          optionsServlet;
     private boolean              supportTrustedProxy = false;
+    private int                  sessionTimeout;
 
-
+    private SecurityContextLogoutHandler logoutHandler;
 
     public AtlasAuthenticationFilter() {
         LOG.info("==> AtlasAuthenticationFilter()");
@@ -193,7 +199,7 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
         optionsServlet = new HttpServlet() {
         };
         optionsServlet.init();
-
+        logoutHandler = new SecurityContextLogoutHandler();
         LOG.info("<== AtlasAuthenticationFilter.init(filterConfig={})", filterConfig);
 
     }
@@ -301,6 +307,10 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
 
         LOG.debug(" AuthenticationFilterConfig: {}", ret);
 
+        sessionTimeout = AtlasConfiguration.SESSION_TIMEOUT_SECS.getInt();
+        if(sessionTimeout < 30){
+            LOG.warn("AtlasAuthenticationFilter:: sessionTimeout is set low");
+        }
         supportKeyTabBrowserLogin = configuration.getBoolean("atlas.authentication.method.kerberos.support.keytab.browser.login", false);
         supportTrustedProxy = configuration.getBoolean("atlas.authentication.method.trustedproxy", true);
         String agents = configuration.getString(AtlasCSRFPreventionFilter.BROWSER_USER_AGENT_PARAM, AtlasCSRFPreventionFilter.BROWSER_USER_AGENTS_DEFAULT);
@@ -332,6 +342,8 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
             Authentication              existingAuth    = SecurityContextHolder.getContext().getAuthentication();
             HttpServletResponse         httpResponse    = (HttpServletResponse) response;
             AtlasResponseRequestWrapper responseWrapper = new AtlasResponseRequestWrapper(httpResponse);
+            String action = httpRequest.getParameter("action");
+            String doAsUser = request.getParameter("doAs");
 
             HeadersUtil.setHeaderMapAttributes(responseWrapper, HeadersUtil.X_FRAME_OPTIONS_KEY);
             HeadersUtil.setHeaderMapAttributes(responseWrapper, HeadersUtil.X_CONTENT_TYPE_OPTIONS_KEY);
@@ -344,6 +356,14 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
                 }
             }
 
+            if (supportTrustedProxy && StringUtils.isNotEmpty(doAsUser) && StringUtils.equals(action, RestUtil.TIMEOUT_ACTION)) {
+                if (existingAuth != null) {
+                    logoutHandler.logout(httpRequest, httpResponse, existingAuth);
+                }
+                redirectTimeoutReqeust(httpRequest, httpResponse);
+                return;
+            }
+
             if (existingAuth == null) {
                 String authHeader = httpRequest.getHeader("Authorization");
 
@@ -365,6 +385,28 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
         }
     }
 
+    private void redirectTimeoutReqeust(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException{
+        String logoutUrl = httpRequest.getRequestURL().toString();
+
+        logoutUrl =  StringUtils.replace(logoutUrl, httpRequest.getRequestURI(), RestUtil.LOGOUT_URL);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("logoutUrl value is " + logoutUrl);
+        }
+        String xForwardedURL = constructForwardableURL(httpRequest);
+
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("xForwardedURL = " + xForwardedURL);
+        }
+        String redirectUrl = RestUtil.constructRedirectURL(httpRequest, logoutUrl, xForwardedURL, ORIGINAL_URL_QUERY_PARAM);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Redirect URL = " + redirectUrl);
+            LOG.debug("session id = " + httpRequest.getRequestedSessionId());
+        }
+
+        httpResponse.sendRedirect(redirectUrl);
+    }
 
 
     /**
@@ -717,7 +759,7 @@ public class AtlasAuthenticationFilter extends AuthenticationFilter {
                 ((AbstractAuthenticationToken) finalAuthentication).setDetails(webDetails);
 
                 SecurityContextHolder.getContext().setAuthentication(finalAuthentication);
-
+                httpRequest.getSession().setMaxInactiveInterval(sessionTimeout);
                 request.setAttribute("atlas.http.authentication.type", true);
 
                 if (!StringUtils.equals(loggedInUser, userName)) {
diff --git a/webapp/src/main/java/org/apache/atlas/web/filters/RestUtil.java b/webapp/src/main/java/org/apache/atlas/web/filters/RestUtil.java
new file mode 100644
index 0000000..01b64d7
--- /dev/null
+++ b/webapp/src/main/java/org/apache/atlas/web/filters/RestUtil.java
@@ -0,0 +1,108 @@
+/**
+ * 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.
+ */
+
+package org.apache.atlas.web.filters;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Enumeration;
+
+public class RestUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RestUtil.class);
+    public static final String TIMEOUT_ACTION = "timeout";
+    public static final String LOGOUT_URL = "/logout.html";
+    private static final String PROXY_ATLAS_URL_PATH = "/atlas";
+    private static final String X_FORWARDED_PROTO = "x-forwarded-proto";
+    private static final String X_FORWARDED_HOST = "x-forwarded-host";
+    private static final String X_FORWARDED_CONTEXT = "x-forwarded-context";
+    public static final String DELIMITTER = "://";
+
+    public static String constructForwardableURL(HttpServletRequest httpRequest) {
+        String xForwardedProto = "";
+        String xForwardedHost = "";
+        String xForwardedContext = "";
+        Enumeration<?> headerNames = httpRequest.getHeaderNames();
+        while (headerNames.hasMoreElements()) {
+            String name = (String) headerNames.nextElement();
+            Enumeration<?> values = httpRequest.getHeaders(name);
+            String value = "";
+            if (values != null) {
+                while (values.hasMoreElements()) {
+                    value = (String) values.nextElement();
+                }
+            }
+            if (StringUtils.trimToNull(name) != null && StringUtils.trimToNull(value) != null) {
+                if (name.equalsIgnoreCase(X_FORWARDED_PROTO)) {
+                    xForwardedProto = value;
+                } else if (name.equalsIgnoreCase(X_FORWARDED_HOST)) {
+                    xForwardedHost = value;
+                } else if (name.equalsIgnoreCase(X_FORWARDED_CONTEXT)) {
+                    xForwardedContext = value;
+                }
+            }
+        }
+        if (xForwardedHost.contains(",")) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("xForwardedHost value is " + xForwardedHost + " it contains multiple hosts, selecting the first host.");
+            }
+            xForwardedHost = xForwardedHost.split(",")[0].trim();
+        }
+        String xForwardedURL = "";
+        if (StringUtils.trimToNull(xForwardedProto) != null) {
+            //if header contains x-forwarded-host and x-forwarded-context
+            if (StringUtils.trimToNull(xForwardedHost) != null && StringUtils.trimToNull(xForwardedContext) != null) {
+                xForwardedURL = xForwardedProto + DELIMITTER + xForwardedHost + xForwardedContext + PROXY_ATLAS_URL_PATH + httpRequest.getRequestURI();
+            } else if (StringUtils.trimToNull(xForwardedHost) != null) {
+                //if header contains x-forwarded-host and does not contains x-forwarded-context
+                xForwardedURL = xForwardedProto + DELIMITTER + xForwardedHost + httpRequest.getRequestURI();
+            } else {
+                //if header does not contains x-forwarded-host and x-forwarded-context
+                //preserve the x-forwarded-proto value coming from the request.
+                String requestURL = httpRequest.getRequestURL().toString();
+                if (StringUtils.trimToNull(requestURL) != null && requestURL.startsWith("http:")) {
+                    requestURL = requestURL.replaceFirst("http", xForwardedProto);
+                }
+                xForwardedURL = requestURL;
+            }
+        }
+        return xForwardedURL;
+    }
+
+    public static String constructRedirectURL(HttpServletRequest request, String redirectUrl, String xForwardedURL, String originalUrlQueryParam) {
+        String delimiter = "?";
+        if (redirectUrl.contains("?")) {
+            delimiter = "&";
+        }
+        String loginURL = redirectUrl + delimiter + originalUrlQueryParam + "=";
+        if (StringUtils.trimToNull(xForwardedURL) != null) {
+            loginURL += xForwardedURL;
+        } else {
+            loginURL += request.getRequestURL().append(getOriginalQueryString(request));
+        }
+        return loginURL;
+    }
+
+    private static String getOriginalQueryString(HttpServletRequest request) {
+        String originalQueryString = request.getQueryString();
+        return (originalQueryString == null) ? "" : "?" + originalQueryString;
+    }
+}
diff --git a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
index 01fb8ec..baa040f 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
@@ -370,6 +370,7 @@ public class AdminResource {
         responseData.put(UI_DATE_FORMAT, uiDateFormat);
         responseData.put(AtlasConfiguration.DEBUG_METRICS_ENABLED.getPropertyName(), isDebugMetricsEnabled);
         responseData.put(AtlasConfiguration.TASKS_USE_ENABLED.getPropertyName(), isTasksEnabled);
+        responseData.put(AtlasConfiguration.SESSION_TIMEOUT_SECS.getPropertyName(), AtlasConfiguration.SESSION_TIMEOUT_SECS.getInt());
 
         String salt = (String) request.getSession().getAttribute(CSRF_TOKEN);
         if (StringUtils.isEmpty(salt)) {
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java b/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
index e7a5d66..1b1a808 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
+++ b/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
@@ -18,6 +18,7 @@
 
 package org.apache.atlas.web.security;
 
+import org.apache.atlas.AtlasConfiguration;
 import org.json.simple.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -25,6 +26,7 @@ import org.springframework.security.core.Authentication;
 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.PostConstruct;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -35,6 +37,14 @@ import java.io.IOException;
 public class AtlasAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
 
     private static Logger LOG = LoggerFactory.getLogger(AuthenticationSuccessHandler.class);
+    private int sessionTimeout = 3600;
+    public static final String LOCALLOGIN = "locallogin";
+
+    @PostConstruct
+    public void setup() {
+        sessionTimeout = AtlasConfiguration.SESSION_TIMEOUT_SECS.getInt();
+    }
+
     @Override
     public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                         Authentication authentication) throws IOException, ServletException {
@@ -45,10 +55,10 @@ public class AtlasAuthenticationSuccessHandler implements AuthenticationSuccessH
         json.put("msgDesc", "Success");
 
         if (request.getSession() != null) { // incase of form based login mark it as local login in session
-            request.getSession().setAttribute("locallogin","true");
-            request.getServletContext().setAttribute(request.getSession().getId(), "locallogin");
+            request.getSession().setAttribute(LOCALLOGIN,"true");
+            request.getServletContext().setAttribute(request.getSession().getId(), LOCALLOGIN);
+            request.getSession().setMaxInactiveInterval(sessionTimeout);
         }
-
         response.setContentType("application/json");
         response.setStatus(HttpServletResponse.SC_OK);
         response.setCharacterEncoding("UTF-8");