mirror of
https://github.com/ansible/awx.git
synced 2026-01-16 04:10:44 -03:30
Session timeout after idle session
This commit is the UI portion of the session timeout feature for 2.4 (not incorporating the session_limit yet). This includes actively ending a session when the user's session time has expired, as well as giving the user a notification one minute prior that their session is about to end. It also includes removing 'session_timeout' from config.js. This is now retrieved from the response headers of each REST call. Each time the user make a rest call the session is extended another 1800 seconds (or whatever amount the user might configure with AUTH_TOKEN_EXPIRATION in local_settings.py)
This commit is contained in:
parent
0cee9b3814
commit
fd34854f7a
@ -55,7 +55,8 @@ import {InventoriesList, InventoriesAdd, InventoriesEdit, InventoriesManage} fro
|
||||
import {AdminsList} from './controllers/Admins';
|
||||
import {UsersList, UsersAdd, UsersEdit} from './controllers/Users';
|
||||
import {TeamsList, TeamsAdd, TeamsEdit} from './controllers/Teams';
|
||||
import './shared/RestServices';
|
||||
|
||||
import RestServices from './rest/main';
|
||||
import './shared/api-loader';
|
||||
import './shared/form-generator';
|
||||
import './shared/Modal';
|
||||
@ -78,7 +79,7 @@ var tower = angular.module('Tower', [
|
||||
'ngRoute',
|
||||
'ngSanitize',
|
||||
'ngCookies',
|
||||
'RestServices',
|
||||
RestServices.name,
|
||||
routeExtensions.name,
|
||||
browserData.name,
|
||||
breadcrumbs.name,
|
||||
@ -878,7 +879,6 @@ var tower = angular.module('Tower', [
|
||||
|
||||
$rootScope.breadcrumbs = [];
|
||||
$rootScope.crumbCache = [];
|
||||
$rootScope.sessionTimer = Timer.init();
|
||||
|
||||
if ($rootScope.removeOpenSocket) {
|
||||
$rootScope.removeOpenSocket();
|
||||
@ -976,12 +976,12 @@ var tower = angular.module('Tower', [
|
||||
}
|
||||
|
||||
if (Authorization.isUserLoggedIn() === false) {
|
||||
if (next.templateUrl !== (urlPrefix + 'partials/login.html')) {
|
||||
if (next.templateUrl !== (urlPrefix + 'login/loginBackDrop.partial.html')) {
|
||||
$location.path('/login');
|
||||
}
|
||||
} else if ($rootScope.sessionTimer.isExpired()) {
|
||||
// gets here on timeout
|
||||
if (next.templateUrl !== (urlPrefix + 'partials/login.html')) {
|
||||
if (next.templateUrl !== (urlPrefix + 'login/loginBackDrop.partial.html')) {
|
||||
$rootScope.sessionTimer.expireSession();
|
||||
if (sock) {
|
||||
sock.socket.socket.disconnect();
|
||||
@ -1010,6 +1010,7 @@ var tower = angular.module('Tower', [
|
||||
$rootScope.user_is_superuser = Authorization.getUserInfo('is_superuser');
|
||||
// when the user refreshes we want to open the socket, except if the user is on the login page, which should happen after the user logs in (see the AuthService module for that call to OpenSocket)
|
||||
if($location.$$url !== '/login'){
|
||||
$rootScope.sessionTimer = Timer.init();
|
||||
$rootScope.$emit('OpenSocket');
|
||||
pendoService.issuePendoIdentity();
|
||||
}
|
||||
|
||||
@ -40,10 +40,6 @@
|
||||
password_hasSymbol: false, // require one of these symbols to be
|
||||
// in the password: -!$%^&*()_+|~=`{}[]:";'<>?,./
|
||||
|
||||
session_timeout: 1800, // Number of seconds before an inactive session is automatically timed out and forced to log in again.
|
||||
// Separate from time out value set in API.
|
||||
|
||||
|
||||
variable_edit_modes: { // Options we pass to ControlMirror for editing YAML/JSON variables
|
||||
yaml: {
|
||||
mode:"text/x-yaml",
|
||||
|
||||
@ -144,7 +144,7 @@ export function JobTemplatesList($scope, $rootScope, $location, $log, $routePara
|
||||
|
||||
|
||||
CreateDialog({
|
||||
id: 'copy-job-modal' ,
|
||||
id: 'copy-job-modal',
|
||||
title: "Copy",
|
||||
scope: $scope,
|
||||
buttons: buttons,
|
||||
|
||||
@ -46,7 +46,7 @@ angular.module('LoadConfigHelper', ['Utilities'])
|
||||
$rootScope.$emit('ConfigReady');
|
||||
}
|
||||
|
||||
}, function(response) {
|
||||
}, function() {
|
||||
//local_settings.json not found
|
||||
$log.info('local_settings.json not found');
|
||||
$rootScope.$emit('ConfigReady');
|
||||
|
||||
@ -94,6 +94,8 @@ export default
|
||||
$rootScope.token_expires = null;
|
||||
$rootScope.login_username = null;
|
||||
$rootScope.login_password = null;
|
||||
clearTimeout($rootScope.idleTimer);
|
||||
clearTimeout($rootScope.endTimer);
|
||||
},
|
||||
|
||||
getLicense: function () {
|
||||
@ -109,7 +111,7 @@ export default
|
||||
|
||||
setLicense: function (data) {
|
||||
var license = data.license_info;
|
||||
license.analytics_status = data.analytics_status;
|
||||
license.analytics_status = data.analytics_status;
|
||||
license.version = data.version;
|
||||
license.tested = false;
|
||||
Store('license', license);
|
||||
@ -138,7 +140,8 @@ export default
|
||||
method: 'GET',
|
||||
url: '/api/v1/me/',
|
||||
headers: {
|
||||
'Authorization': 'Token ' + this.getToken()
|
||||
'Authorization': 'Token ' + this.getToken(),
|
||||
"X-Auth-Token": 'Token ' + this.getToken()
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
* @description
|
||||
*/
|
||||
export default
|
||||
['$rootScope', '$cookieStore', '$location', 'GetBasePath', 'Empty',
|
||||
function ($rootScope, $cookieStore) {
|
||||
['$rootScope', '$cookieStore', 'transitionTo', 'CreateDialog', 'Authorization',
|
||||
function ($rootScope, $cookieStore, transitionTo, CreateDialog, Authorization) {
|
||||
return {
|
||||
|
||||
sessionTime: null,
|
||||
@ -46,10 +46,25 @@ export default
|
||||
}
|
||||
},
|
||||
|
||||
isIdle: function() {
|
||||
var stime = this.getSessionTime()/1000,
|
||||
now = new Date().getTime()/1000,
|
||||
diff = stime-now;
|
||||
|
||||
if(diff < 61){
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
expireSession: function () {
|
||||
this.sessionTime = 0;
|
||||
$rootScope.sessionExpired = true;
|
||||
this.clearTimers();
|
||||
$cookieStore.put('sessionExpired', true);
|
||||
transitionTo('signOut');
|
||||
},
|
||||
|
||||
moveForward: function () {
|
||||
@ -60,6 +75,70 @@ export default
|
||||
$cookieStore.put('sessionTime', t);
|
||||
$rootScope.sessionExpired = false;
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
|
||||
this.startTimers();
|
||||
},
|
||||
|
||||
startTimers: function() {
|
||||
var that = this,
|
||||
tm = ($AnsibleConfig) ? $AnsibleConfig.session_timeout : 1800,
|
||||
t = tm - 60;
|
||||
|
||||
this.clearTimers();
|
||||
|
||||
// make a timeout that will go off in 30 mins to log them out
|
||||
// unless they extend their time
|
||||
$rootScope.endTimer = setTimeout(function(){
|
||||
that.expireSession();
|
||||
}, tm * 1000);
|
||||
|
||||
// notify the user a minute before the end of their session that
|
||||
// their session is about to expire
|
||||
if($rootScope.idleTimer){
|
||||
clearTimeout($rootScope.idleTimer);
|
||||
}
|
||||
$rootScope.idleTimer = setTimeout(function() {
|
||||
if(that.isIdle() === true){
|
||||
var buttons = [{
|
||||
"label": "Continue",
|
||||
"onClick": function() {
|
||||
// make a rest call here to force the API to
|
||||
// move the session time forward
|
||||
Authorization.getUser();
|
||||
that.moveForward();
|
||||
$(this).dialog('close');
|
||||
|
||||
},
|
||||
"class": "btn btn-primary",
|
||||
"id": "idle-modal-button"
|
||||
}];
|
||||
|
||||
if ($rootScope.removeIdleDialogReady) {
|
||||
$rootScope.removeIdleDialogReady();
|
||||
}
|
||||
$rootScope.removeIdleDialogReady = $rootScope.$on('IdleDialogReady', function() {
|
||||
$('#idle-modal').show();
|
||||
$('#idle-modal').dialog('open');
|
||||
});
|
||||
CreateDialog({
|
||||
id: 'idle-modal' ,
|
||||
title: "Idle Session",
|
||||
scope: $rootScope,
|
||||
buttons: buttons,
|
||||
width: 470,
|
||||
height: 240,
|
||||
minWidth: 200,
|
||||
callback: 'IdleDialogReady'
|
||||
});
|
||||
}
|
||||
}, t * 1000);
|
||||
|
||||
|
||||
},
|
||||
|
||||
clearTimers: function(){
|
||||
clearTimeout($rootScope.idleTimer);
|
||||
clearTimeout($rootScope.endTimer);
|
||||
},
|
||||
|
||||
init: function () {
|
||||
|
||||
@ -13,10 +13,5 @@ export default {
|
||||
Authorization.logout();
|
||||
$location.path('/login');
|
||||
}],
|
||||
templateUrl: '/static/partials/blank.html',
|
||||
resolve: {
|
||||
features: ['FeaturesService', function(FeaturesService) {
|
||||
return FeaturesService.get();
|
||||
}]
|
||||
}
|
||||
templateUrl: '/static/partials/blank.html'
|
||||
};
|
||||
|
||||
26
awx/ui/client/src/rest/interceptors.service.js
Normal file
26
awx/ui/client/src/rest/interceptors.service.js
Normal file
@ -0,0 +1,26 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default
|
||||
['$rootScope',
|
||||
function ($rootScope) {
|
||||
return {
|
||||
response: function(config) {
|
||||
if(config.headers('auth-token-timeout') !== null){
|
||||
// $rootScope.sessionTimer = Number(config.headers('auth-token-timeout'));
|
||||
$AnsibleConfig.session_timeout = Number(config.headers('auth-token-timeout'));
|
||||
// $rootScope.sessionTimer = Timer.init();
|
||||
}
|
||||
return config;
|
||||
}
|
||||
};
|
||||
}];
|
||||
16
awx/ui/client/src/rest/main.js
Normal file
16
awx/ui/client/src/rest/main.js
Normal file
@ -0,0 +1,16 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import restServicesFactory from './restServices.factory';
|
||||
import interceptors from './interceptors.service';
|
||||
|
||||
export default
|
||||
angular.module('RestServices', [])
|
||||
.config(['$httpProvider', function($httpProvider) {
|
||||
$httpProvider.interceptors.push('RestInterceptor');
|
||||
}])
|
||||
.factory('Rest', restServicesFactory)
|
||||
.service('RestInterceptor', interceptors);
|
||||
@ -55,8 +55,7 @@
|
||||
*/
|
||||
|
||||
export default
|
||||
angular.module('RestServices', ['ngCookies'])
|
||||
.factory('Rest', ['$http', '$rootScope', '$cookieStore', '$q', 'Authorization',
|
||||
['$http', '$rootScope', '$cookieStore', '$q', 'Authorization',
|
||||
function ($http, $rootScope, $cookieStore, $q, Authorization) {
|
||||
return {
|
||||
|
||||
@ -269,4 +268,4 @@ angular.module('RestServices', ['ngCookies'])
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
];
|
||||
@ -4,7 +4,7 @@ import '../support/node';
|
||||
|
||||
import {describeModule} from '../support/describe-module';
|
||||
import 'shared/Utilities';
|
||||
import 'shared/RestServices';
|
||||
|
||||
import JobStatusGraph from 'dashboard/graphs/job-status/main';
|
||||
|
||||
var resizeHandler = sinon.spy();
|
||||
|
||||
@ -58,6 +58,7 @@
|
||||
|
||||
<!-- Password Dialog -->
|
||||
<div id="password-modal" style="display: none;"></div>
|
||||
<div id="idle-modal" style="display:none">Your session will expire in 1 minute, would you like to continue?</div>
|
||||
|
||||
<!-- Generic Form dialog -->
|
||||
<div id="form-modal" class="modal fade">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user