security: update lastactivity when on audit logs.

- The previous update on each call was to expensive and created lot of DB locks in high traffic env
This commit is contained in:
Marcin Kuzminski 2018-07-31 22:52:44 +02:00
parent d6757c3989
commit ecff3dbaed
8 changed files with 49 additions and 26 deletions

View file

@ -208,6 +208,7 @@ def request_view(request):
# register our auth-user
request.rpc_user = auth_u
request.environ['rc_auth_user_id'] = auth_u.user_id
# now check if token is valid for API
auth_token = request.rpc_api_key

View file

@ -76,6 +76,8 @@ class TestUpdateUser(object):
'user': ret
}
expected = ret
expected['user']['last_activity'] = response.json['result']['user'][
'last_activity']
assert_ok(id_, expected, given=response.body)
def test_api_update_user_by_user_id(self):
@ -91,6 +93,8 @@ class TestUpdateUser(object):
'user': ret
}
expected = ret
expected['user']['last_activity'] = response.json['result']['user'][
'last_activity']
assert_ok(id_, expected, given=response.body)
def test_api_update_user_default_user(self):

View file

@ -25,13 +25,13 @@ import collections
import tempfile
from paste.gzipper import make_gzip_middleware
import pyramid.events
from pyramid.wsgi import wsgiapp
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.config import Configurator
from pyramid.settings import asbool, aslist
from pyramid.httpexceptions import (
HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
from pyramid.events import ApplicationCreated
from pyramid.renderers import render_to_response
from rhodecode.model import meta
@ -39,6 +39,7 @@ from rhodecode.config import patches
from rhodecode.config import utils as config_utils
from rhodecode.config.environment import load_pyramid_environment
import rhodecode.events
from rhodecode.lib.middleware.vcs import VCSMiddleware
from rhodecode.lib.request import Request
from rhodecode.lib.vcs import VCSCommunicationError
@ -268,11 +269,14 @@ def includeme(config):
settings['default_locale_name'] = settings.get('lang', 'en')
# Add subscribers.
config.add_subscriber(inject_app_settings, ApplicationCreated)
config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
config.add_subscriber(inject_app_settings,
pyramid.events.ApplicationCreated)
config.add_subscriber(scan_repositories_if_enabled,
pyramid.events.ApplicationCreated)
config.add_subscriber(write_metadata_if_needed,
pyramid.events.ApplicationCreated)
config.add_subscriber(write_js_routes_if_enabled,
pyramid.events.ApplicationCreated)
# request custom methods
config.add_request_method(

View file

@ -32,9 +32,11 @@ def trigger(event, registry=None):
# For the first step we are using pyramids thread locals here. If the
# event mechanism works out as a good solution we should think about
# passing the registry as an argument to get rid of it.
event_name = event.__class__
log.debug('event %s sent for execution', event_name)
registry = registry or get_current_registry()
registry.notify(event)
log.debug('event %s triggered using registry %s', event.__class__, registry)
log.debug('event %s triggered using registry %s', event_name, registry)
# Send the events to integrations directly
from rhodecode.integrations import integrations_event_handler

View file

@ -241,20 +241,24 @@ def store(action, user, action_data=None, user_data=None, ip_addr=None,
action_name = safe_unicode(action)
ip_address = safe_unicode(ip_addr)
user_log = _store_log(
action_name=action_name,
action_data=action_data or {},
user_id=user_id,
username=username,
user_data=user_data or {},
ip_address=ip_address,
repository_id=repository_id,
repository_name=repository_name
)
with sa_session.no_autoflush:
update_user_last_activity(sa_session, user_id)
sa_session.add(user_log)
if commit:
sa_session.commit()
user_log = _store_log(
action_name=action_name,
action_data=action_data or {},
user_id=user_id,
username=username,
user_data=user_data or {},
ip_address=ip_address,
repository_id=repository_id,
repository_name=repository_name
)
sa_session.add(user_log)
if commit:
sa_session.commit()
entry_id = user_log.entry_id or ''
log.info('AUDIT[%s]: Logging action: `%s` by user:id:%s[%s] ip:%s',
@ -262,3 +266,14 @@ def store(action, user, action_data=None, user_data=None, ip_addr=None,
except Exception:
log.exception('AUDIT: failed to store audit log')
def update_user_last_activity(sa_session, user_id):
_last_activity = datetime.datetime.now()
try:
sa_session.query(User).filter(User.user_id == user_id).update(
{"last_activity": _last_activity})
log.debug(
'updated user `%s` last activity to:%s', user_id, _last_activity)
except Exception:
log.exception("Failed last activity update")

View file

@ -521,6 +521,7 @@ class SimpleVCS(object):
if not self.valid_and_active_user(user):
return HTTPForbidden()(environ, start_response)
username = user.username
user_id = user.user_id
# check user attributes for password change flag
user_obj = user
@ -536,6 +537,7 @@ class SimpleVCS(object):
plugin, plugin_cache_active, cache_ttl)
if not perm:
return HTTPForbidden()(environ, start_response)
environ['rc_auth_user_id'] = user_id
# extras are injected into UI object and later available
# in hooks executed by RhodeCode

View file

@ -931,12 +931,6 @@ class User(Base, BaseModel):
Session().add(self)
log.debug('updated user %s lastlogin', self.username)
def update_lastactivity(self):
"""Update user lastactivity"""
self.last_activity = datetime.datetime.now()
Session().add(self)
log.debug('updated user `%s` last activity', self.username)
def update_password(self, new_password):
from rhodecode.lib.auth import get_crypt_password

View file

@ -100,6 +100,7 @@ def add_request_user_context(event):
auth_user = get_auth_user(request)
request.user = auth_user
request.environ['rc_auth_user'] = auth_user
request.environ['rc_auth_user_id'] = auth_user.user_id
request.environ['rc_req_id'] = req_id