diff options
author | John Dennis <jdennis@redhat.com> | 2012-02-19 10:02:38 -0500 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2012-02-27 05:55:15 -0500 |
commit | 059a90702e454b99490031bd37541304e65d35d2 (patch) | |
tree | 4b0c896c19cbac6c3f15e9fabfe1a7558b1c5f94 /ipalib/session.py | |
parent | 9753fd423059e8d5725ead9a90a7cf1b9e0b9b85 (diff) | |
download | freeipa-059a90702e454b99490031bd37541304e65d35d2.tar.gz freeipa-059a90702e454b99490031bd37541304e65d35d2.tar.xz freeipa-059a90702e454b99490031bd37541304e65d35d2.zip |
Implement session activity timeout
Previously sessions expired after session_auth_duration had elapsed
commencing from the start of the session. We new support a "rolling"
expiration where the expiration is advanced by session_auth_duration
everytime the session is accessed, this is equivalent to a inactivity
timeout. The expiration is still constrained by the credential
expiration in all cases. The session expiration behavior is
configurable based on the session_auth_duration_type.
* Reduced the default session_auth_duration from 1 hour to 20 minutes.
* Replaced the sesssion write_timestamp with the access_timestamp and
update the access_timestamp whenever the session data is created,
retrieved, or written.
* Modify set_session_expiration_time to handle both an inactivity
timeout and a fixed duration.
* Introduce KerberosSession as a mixin class to share session
duration functionality with all classes manipulating session data
with Kerberos auth. This is both the non-RPC login class and the RPC
classes.
* Update make-lint to handle new classes.
* Added session_auth_duration_type config item.
* Updated default.conf.5 man page for new session_auth_duration_type item.
* Removed these unused config items: mount_xmlserver,
mount_jsonserver, webui_assets_dir
https://fedorahosted.org/freeipa/ticket/2392
Diffstat (limited to 'ipalib/session.py')
-rw-r--r-- | ipalib/session.py | 83 |
1 files changed, 63 insertions, 20 deletions
diff --git a/ipalib/session.py b/ipalib/session.py index 1f5ee379d..5c71a92b6 100644 --- a/ipalib/session.py +++ b/ipalib/session.py @@ -626,7 +626,7 @@ mod_auth_kerb. Everything else remains the same. #------------------------------------------------------------------------------- -default_max_session_lifetime = 60*60 # number of seconds +default_max_session_duration = 60*60 # number of seconds ISO8601_DATETIME_FMT = '%Y-%m-%dT%H:%M:%S' # FIXME jrd, this should be defined elsewhere def fmt_time(timestamp): @@ -888,8 +888,8 @@ class MemcacheSessionManager(SessionManager): The session ID used to identify this session data. session_start_timestamp Timestamp when this session was created. - session_write_timestamp - Timestamp when the session was last written to cache. + session_access_timestamp + Timestamp when the session was last accessed. session_expiration_timestamp Timestamp when session expires. Defaults to zero which implies no expiration. See `set_session_expiration_time()`. @@ -904,7 +904,7 @@ class MemcacheSessionManager(SessionManager): now = time.time() return {'session_id' : session_id, 'session_start_timestamp' : now, - 'session_write_timestamp' : now, + 'session_access_timestamp' : now, 'session_expiration_timestamp' : 0, } @@ -934,6 +934,12 @@ class MemcacheSessionManager(SessionManager): ''' session_key = self.session_key(session_id) session_data = self.mc.get(session_key) + + if session_data is not None: + # update the access timestamp + now = time.time() + session_data['session_access_timestamp'] = now + return session_data def get_session_id_from_http_cookie(self, cookie_header): @@ -1028,14 +1034,17 @@ class MemcacheSessionManager(SessionManager): ''' session_id = session_data['session_id'] session_key = self.session_key(session_id) + + # update the access timestamp now = time.time() - session_data['session_write_timestamp'] = now + session_data['session_access_timestamp'] = now + session_expiration_timestamp = session_data['session_expiration_timestamp'] - self.debug('store session: session_id=%s start_timestamp=%s write_timestamp=%s expiration_timestamp=%s', + self.debug('store session: session_id=%s start_timestamp=%s access_timestamp=%s expiration_timestamp=%s', session_id, fmt_time(session_data['session_start_timestamp']), - fmt_time(session_data['session_write_timestamp']), + fmt_time(session_data['session_access_timestamp']), fmt_time(session_data['session_expiration_timestamp'])) self.mc.set(session_key, session_data, time=session_expiration_timestamp) @@ -1072,8 +1081,8 @@ class MemcacheSessionManager(SessionManager): return result def set_session_expiration_time(self, session_data, - lifetime=default_max_session_lifetime, - max_age=None): + duration=default_max_session_duration, + max_age=None, duration_type='inactivity_timeout'): ''' memcached permits setting an expiration time on entries. The expiration time may either be Unix time (number of seconds since @@ -1088,10 +1097,24 @@ class MemcacheSessionManager(SessionManager): constraints. When a session is created it's start time is recorded in the - session data as the session_start_timestamp value. The - expiration timestamp is computed by adding the lifetime to the - session_start_timestamp. Then if the max_age is specified the - expiration is constrained to be not greater than the max_age. + session data as the session_start_timestamp value. + + There are two ways the expiration timestamp can be computed: + + from_start + A session has a fixed duration beginning with the start of + the session. The session expires when the duration + interval has elapsed relative to the start of the session. + inactivity_timeout + A session times out after a period of inactivity. The + expiration time is advanced by the value of the duration + interval everytime the session is updated. + + After the expiration is computed it may be capped at a maximum + value due to other constraints (e.g. authentication credential + expiration). If the optional max_age parameter is specified + then expiration is constrained to be not greater than the + max_age. The final computed expiration is then written into the session_data as the session_expiration_timestamp value. The @@ -1107,31 +1130,51 @@ class MemcacheSessionManager(SessionManager): :parameters: session_data Session data dict, must contain session_id key. - lifetime + duration Number of seconds cache entry should live. This is a duration value, not a timestamp. Zero implies no expiration. - - max_age + max_age Unix time value when cache entry must expire by. :returns: expiration timestamp, zero implies no expiration ''' - if lifetime == 0 and max_age is None: + if duration == 0 and max_age is None: + # No expiration expiration = 0 session_data['session_expiration_timestamp'] = expiration return expiration - session_start_timestamp = session_data['session_start_timestamp'] - expiration = session_start_timestamp + lifetime - + if duration_type == 'inactivity_timeout': + now = time.time() + session_data['session_access_timestamp'] = now + expiration = now + duration + elif duration_type == 'from_start': + session_start_timestamp = session_data['session_start_timestamp'] + expiration = session_start_timestamp + duration + else: + # Don't throw an exception, it's critical the session be + # given some expiration, instead log the error and execute + # a default action of expiring the session 5 minutes after + # it was initiated (similar to from_start but with + # hardcoded duration) + default = 60*5 + self.warning('unknown session duration_type (%s), defaulting to %s seconds from session start', + duration_type, default) + session_start_timestamp = session_data['session_start_timestamp'] + expiration = session_start_timestamp + default + + # Cap the expiration if max_age is specified if max_age is not None: expiration = min(expiration, max_age) session_data['session_expiration_timestamp'] = expiration + self.debug('set_session_expiration_time: duration_type=%s duration=%s max_age=%s expiration=%s (%s)', + duration_type, duration, max_age, expiration, fmt_time(expiration)) + return expiration def delete_session_data(self, session_id): |