« [Article] Customizing Security for Servoy Solutions | Main | [Events] November VUG tomorrow »
November 08, 2007
[Tip] Automating disconnecting idle clients
by David Workman
Data Mosaic
For security reasons and license use efficiency, disconnecting idle clients is a good thing. Unfortunately, Servoy doesn't have a function to accomplish this programmatically. The only way to disconnect clients at the moment is manually via the Servoy admin application:
This is also the only place where Servoy gives you a hint as to what the current idle time of a client is (this data is not stored in the repository).
The solution to automate this is to process the Servoy admin client pages with curl every so many minutes, check for any clients who are over the idle time limit you specify, and then disconnect them with an additional curl call.
Put the following code in a batch processor and you're good to go! Works with Servoy 2.2x through 3.5.2. It's a bit of a hack and I was lazy with the code (should have used regex for everything but it gave me a headache) -- but it works like a champ.
(Note for windows users: make sure curl is installed for starters. Off the top of my head I think that the executeProgram(...) call has to be formatted a bit differently as well. There are several forum posts on how to use this function with windows you can look up.)
/*****
auto shutdown clients who are idle
*****/
//setup
var minutesAllowed = 120
//get page
var user = "admin"
var password = "password"
var address = "localhost:8080"
var x = application.executeProgram(
'curl',
'-u',
user + ":" + password,
address + '/servoy-admin/clients');
//process all clients
while (x.search(/clients\/info/) != -1) {
//get user ID
var userIDStart = x.search(/clients\/info/)
var userID = x.substring(userIDStart + 13, userIDStart + 49)
//get login time
var loginStart = x.search(/User logged in\:<td>/)
var loginEnd = x.search(/<tr><td>Solution opened:/)
var login = new Date(x.substring(loginStart + 19, loginEnd))
//get idle time
var idleStart = x.search(/<td>User idle since/)
var idleEnd = x.search(/< /table>\n< /table>\n< /td>/)
var idle = new Date(x.substring(idleStart + 24, idleStart + 24 + 28))
//logic for closing and idle client
if (new Date() - idle > (1000 * 60 * minutesAllowed)) {
//get additional info from repository server, table servoy_client_stats
var dataset = databaseManager.getDataSetByQuery(
"repository_server",
"select server_name, server_ip from servoy_client_stats where client_id = ?",
[userID],
1)
var infoHTML = application.executeProgram(
'curl',
'-u',
user + ":" + password,
address + '/servoy-admin/clients/info/' + userID)
var infoStart = infoHTML.search(/User ID:/)
var infoEnd = infoHTML.search(/<\!-- User ID end/)
var infoExtra = infoHTML.substring(infoStart + 15, infoEnd - 5)
//(*optional*) log action in a log table
controller.newRecord()
//data from servoy-admin clients list page
client_id = userID
start_time = login
idle_time = idle
//data from repository server
server_name = dataset.getValue(1,1)
server_ip = dataset.getValue(1,2)
//data from servoy-admin client information detail page
extra_info = infoExtra
controller.saveData()
//shutdown client
application.executeProgram(
'curl',
'-u',
user + ":" + password,
address + '/servoy-admin/clients/shutdown/client/' + userID + "?confirm=Shutdown%21")
}
//remove client from processing string
x = x.substring(idleStart + 24 + 28, 50000)
}
| Posted by David Workman on November 8, 2007 at 03:18 PM in Tips | Permalink
Comments
As it turns out, session can actually be monitored, maintained and expired by using scheduler. What I do is create a scheduler at login (for the current user) that runs a logout script after x seconds. Each time an action is performed e.g. edit or save or rollback, back, forward etc., I dump the original scheduler and re-create it with a new logout time later in the future - just like it works on the web.
Very simple methods that work great...
/**
* gSessionStart
*
* Create a scheduler job that logs a user out (via gSessionExpire) after an amount
* of inactivity specified by globals.g_session_length
*
* @author Jeff Bader
**/
var start_date = new Date();
start_date.setTime(start_date.getTime() + globals.g_session_length);
// Only start session monitoring for smart clients
if (application.getApplicationType() == 2)
{
// Remove scheduler job if one exists before creating a new one (to allow for renewing session)
plugins.scheduler.removeJob('session_monitor_' + security.getUserName());
application.output(plugins.scheduler.addJob('session_monitor_' + security.getUserName(), start_date, gSessionExpire));
}
/**
* gSessionExpire
*
* Log a user out if scheduler detects defined period of session inactivity
*
* @author Jeff Bader
**/
security.logout();
Posted by: Jeff Bader | Nov 8, 2007 3:54:32 PM
Whoa...just how cool is that?!!!
Posted by: David Workman | Nov 8, 2007 4:05:21 PM
be carefull, the batchprocessor will not work, if you have a scheduler allready running in your client. (for instance we check every minute if certain tasks are in alarm status.) the scheduler updates the idle time of the client every minute, so the batchprocessor still 'thinks' that the client is active and will not kill it.
Posted by: Harjo Kompagnie | Nov 9, 2007 3:35:14 AM
Fantastic tips, guys! Very helpful and practical stuff. Talk about giving back control to the developer...
Posted by: Ben Savignac | Nov 9, 2007 6:17:12 AM
