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:
parent
d6757c3989
commit
ecff3dbaed
8 changed files with 49 additions and 26 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue