##// END OF EJS Templates
pull-requests: add merge check that detects WIP marker in title. This will prevent merges in such case....
pull-requests: add merge check that detects WIP marker in title. This will prevent merges in such case. Usually WIP in title means unfinished task that needs still some work. This pattern is present in Gitlab/Github and is already quite common.

File last commit:

r3679:4cc4558e new-ui
r4099:c12e69d0 default
Show More
audit_logger.py
291 lines | 9.2 KiB | text/x-python | PythonLexer
audit-logs: introducing new audit logger for actions....
r1694 # -*- coding: utf-8 -*-
docs: updated copyrights to 2019
r3363 # Copyright (C) 2017-2019 RhodeCode GmbH
audit-logs: introducing new audit logger for actions....
r1694 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
import datetime
audit-logger: use raw JSON with empty data to control unicode decode warnings....
r2184 from rhodecode.lib.jsonalchemy import JsonRaw
audit-logs: introducing new audit logger for actions....
r1694 from rhodecode.model import meta
audit-logs: add push/pull actions to audit logs.
r1736 from rhodecode.model.db import User, UserLog, Repository
audit-logs: introducing new audit logger for actions....
r1694
log = logging.getLogger(__name__)
audit-logs: added audit-logs on user actions....
r1801 # action as key, and expected action_data as value
audit-logs: implemented pull request and comment events.
r1807 ACTIONS_V1 = {
audit-logs: fill in some default values for the expected action data.
r1802 'user.login.success': {'user_agent': ''},
'user.login.failure': {'user_agent': ''},
'user.logout': {'user_agent': ''},
audit-logs: added user.register audit log entry.
r2384 'user.register': {},
audit-logs: use new v2 api on login/logout/password reset views.
r1697 'user.password.reset_request': {},
audit-logs: fill in some default values for the expected action data.
r1802 'user.push': {'user_agent': '', 'commit_ids': []},
'user.pull': {'user_agent': ''},
audit-logs: use new v2 api on login/logout/password reset views.
r1697
audit-logs: added audit-logs on user actions....
r1801 'user.create': {'data': {}},
'user.delete': {'old_data': {}},
'user.edit': {'old_data': {}},
'user.edit.permissions': {},
audit-logs: updated action data attrbiutes.
r1823 'user.edit.ip.add': {'ip': {}, 'user': {}},
'user.edit.ip.delete': {'ip': {}, 'user': {}},
'user.edit.token.add': {'token': {}, 'user': {}},
'user.edit.token.delete': {'token': {}, 'user': {}},
'user.edit.email.add': {'email': ''},
'user.edit.email.delete': {'email': ''},
users: added SSH key management for user admin pages
r1993 'user.edit.ssh_key.add': {'token': {}, 'user': {}},
'user.edit.ssh_key.delete': {'token': {}, 'user': {}},
audit-logs: added audit-logs on user actions....
r1801 'user.edit.password_reset.enabled': {},
'user.edit.password_reset.disabled': {},
audit-logs: added audit logs on user groups admin page.
r1805 'user_group.create': {'data': {}},
'user_group.delete': {'old_data': {}},
'user_group.edit': {'old_data': {}},
'user_group.edit.permissions': {},
audit-logs: implemented full audit logs across application....
r1829 'user_group.edit.member.add': {'user': {}},
'user_group.edit.member.delete': {'user': {}},
audit-logs: added audit logs on user groups admin page.
r1805
audit-logs: fill in some default values for the expected action data.
r1802 'repo.create': {'data': {}},
audit-logs: moved async tasks from old deprecated action_logger.
r1803 'repo.fork': {'data': {}},
audit-logs: fill in some default values for the expected action data.
r1802 'repo.edit': {'old_data': {}},
repo-permissions: moved permissions into pyramid....
r1734 'repo.edit.permissions': {},
audit-logs: added entries for branch permissions
r3025 'repo.edit.permissions.branch': {},
repositories: added option to archive repositories instead of deleting them....
r3090 'repo.archive': {'old_data': {}},
audit-logs: fill in some default values for the expected action data.
r1802 'repo.delete': {'old_data': {}},
audit-logs: added entries for branch permissions
r3025
audit-logs: updated action data attrbiutes.
r1823 'repo.archive.download': {'user_agent': '', 'archive_name': '',
'archive_spec': '', 'archive_cached': ''},
audit-logs: added entries for branch permissions
r3025
'repo.permissions.branch_rule.create': {},
'repo.permissions.branch_rule.edit': {},
'repo.permissions.branch_rule.delete': {},
audit-logs: implemented pull request and comment events.
r1807 'repo.pull_request.create': '',
'repo.pull_request.edit': '',
'repo.pull_request.delete': '',
'repo.pull_request.close': '',
'repo.pull_request.merge': '',
'repo.pull_request.vote': '',
'repo.pull_request.comment.create': '',
'repo.pull_request.comment.delete': '',
'repo.pull_request.reviewer.add': '',
'repo.pull_request.reviewer.delete': '',
audit-logs: added entries for branch permissions
r3025 'repo.commit.strip': {'commit_id': ''},
audit-logs: implemented full audit logs across application....
r1829 'repo.commit.comment.create': {'data': {}},
'repo.commit.comment.delete': {'data': {}},
audit-logs: implemented pull request and comment events.
r1807 'repo.commit.vote': '',
artifacts: added reading of metadata and define basic audit-log entries for add/delete artifact
r3679 'repo.artifact.add': '',
'repo.artifact.delete': '',
audit-logs: fill in some default values for the expected action data.
r1802 'repo_group.create': {'data': {}},
'repo_group.edit': {'old_data': {}},
audit-logs: added action logs for repository groups.
r1799 'repo_group.edit.permissions': {},
audit-logs: fill in some default values for the expected action data.
r1802 'repo_group.delete': {'old_data': {}},
audit-logs: introducing new audit logger for actions....
r1694 }
audit-logs: added entries for branch permissions
r3025
audit-logs: implemented pull request and comment events.
r1807 ACTIONS = ACTIONS_V1
audit-logs: introducing new audit logger for actions....
r1694
audit-logs: implement enum sources that should be re-used.
r1798 SOURCE_WEB = 'source_web'
SOURCE_API = 'source_api'
audit-logs: introducing new audit logger for actions....
r1694
class UserWrap(object):
"""
Fake object used to imitate AuthUser
"""
def __init__(self, user_id=None, username=None, ip_addr=None):
self.user_id = user_id
self.username = username
self.ip_addr = ip_addr
audit-logs: add push/pull actions to audit logs.
r1736 class RepoWrap(object):
"""
Fake object used to imitate RepoObject that audit logger requires
"""
def __init__(self, repo_id=None, repo_name=None):
self.repo_id = repo_id
self.repo_name = repo_name
audit-logs: introducing new audit logger for actions....
r1694 def _store_log(action_name, action_data, user_id, username, user_data,
ip_address, repository_id, repository_name):
user_log = UserLog()
user_log.version = UserLog.VERSION_2
user_log.action = action_name
audit-logger: use raw JSON with empty data to control unicode decode warnings....
r2184 user_log.action_data = action_data or JsonRaw(u'{}')
audit-logs: introducing new audit logger for actions....
r1694
user_log.user_ip = ip_address
user_log.user_id = user_id
user_log.username = username
audit-logger: use raw JSON with empty data to control unicode decode warnings....
r2184 user_log.user_data = user_data or JsonRaw(u'{}')
audit-logs: introducing new audit logger for actions....
r1694
user_log.repository_id = repository_id
user_log.repository_name = repository_name
user_log.action_date = datetime.datetime.now()
return user_log
audit-logger: added convinience wrappers to store web or api action.
r1800 def store_web(*args, **kwargs):
if 'action_data' not in kwargs:
kwargs['action_data'] = {}
kwargs['action_data'].update({
'source': SOURCE_WEB
})
return store(*args, **kwargs)
def store_api(*args, **kwargs):
if 'action_data' not in kwargs:
kwargs['action_data'] = {}
kwargs['action_data'].update({
'source': SOURCE_API
})
return store(*args, **kwargs)
audit-logs: added audit-logs on user actions....
r1801 def store(action, user, action_data=None, user_data=None, ip_addr=None,
repo=None, sa_session=None, commit=False):
audit-logs: introducing new audit logger for actions....
r1694 """
audit-logger: added convinience wrappers to store web or api action.
r1800 Audit logger for various actions made by users, typically this
results in a call such::
audit-logs: introducing new audit logger for actions....
r1694
from rhodecode.lib import audit_logger
audit-logger: added entry for archive download.
r1743 audit_logger.store(
audit-logs: implemented full audit logs across application....
r1829 'repo.edit', user=self._rhodecode_user)
audit-logger: added entry for archive download.
r1743 audit_logger.store(
audit-logs: implemented full audit logs across application....
r1829 'repo.delete', action_data={'data': repo_data},
audit-logger: added entry for archive download.
r1743 user=audit_logger.UserWrap(username='itried-login', ip_addr='8.8.8.8'))
# repo action
audit_logger.store(
audit-logs: implemented full audit logs across application....
r1829 'repo.delete',
audit-logger: added entry for archive download.
r1743 user=audit_logger.UserWrap(username='itried-login', ip_addr='8.8.8.8'),
repo=audit_logger.RepoWrap(repo_name='some-repo'))
# repo action, when we know and have the repository object already
audit_logger.store(
audit-logs: implemented full audit logs across application....
r1829 'repo.delete', action_data={'source': audit_logger.SOURCE_WEB, },
audit-logs: implement enum sources that should be re-used.
r1798 user=self._rhodecode_user,
audit-logger: added entry for archive download.
r1743 repo=repo_object)
audit-logs: introducing new audit logger for actions....
r1694
audit-logger: added convinience wrappers to store web or api action.
r1800 # alternative wrapper to the above
audit_logger.store_web(
audit-logs: implemented full audit logs across application....
r1829 'repo.delete', action_data={},
audit-logger: added convinience wrappers to store web or api action.
r1800 user=self._rhodecode_user,
repo=repo_object)
audit-logs: introducing new audit logger for actions....
r1694 # without an user ?
audit-logger: added entry for archive download.
r1743 audit_logger.store(
audit-logs: implemented full audit logs across application....
r1829 'user.login.failure',
audit-logger: added entry for archive download.
r1743 user=audit_logger.UserWrap(
username=self.request.params.get('username'),
ip_addr=self.request.remote_addr))
audit-logs: introducing new audit logger for actions....
r1694 """
from rhodecode.lib.utils2 import safe_unicode
from rhodecode.lib.auth import AuthUser
audit-logs: fill in some default values for the expected action data.
r1802 action_spec = ACTIONS.get(action, None)
if action_spec is None:
raise ValueError('Action `{}` is not supported'.format(action))
audit-logs: introducing new audit logger for actions....
r1694
if not sa_session:
sa_session = meta.Session()
try:
username = getattr(user, 'username', None)
if not username:
pass
user_id = getattr(user, 'user_id', None)
if not user_id:
# maybe we have username ? Try to figure user_id from username
if username:
user_id = getattr(
User.get_by_username(username), 'user_id', None)
ip_addr = ip_addr or getattr(user, 'ip_addr', None)
if not ip_addr:
pass
if not user_data:
# try to get this from the auth user
if isinstance(user, AuthUser):
audit-logger: store some user details on we have proper object of auth-user.
r1701 user_data = {
'username': user.username,
'email': user.email,
}
audit-logs: introducing new audit logger for actions....
r1694
audit-logs: add push/pull actions to audit logs.
r1736 repository_name = getattr(repo, 'repo_name', None)
audit-logs: introducing new audit logger for actions....
r1694 repository_id = getattr(repo, 'repo_id', None)
audit-logs: add push/pull actions to audit logs.
r1736 if not repository_id:
# maybe we have repo_name ? Try to figure repo_id from repo_name
if repository_name:
repository_id = getattr(
Repository.get_by_repo_name(repository_name), 'repo_id', None)
audit-logs: introducing new audit logger for actions....
r1694
audit-logs: allow showing individual entries for audit log.
r2110 action_name = safe_unicode(action)
ip_address = safe_unicode(ip_addr)
security: update lastactivity when on audit logs....
r2930 with sa_session.no_autoflush:
update_user_last_activity(sa_session, user_id)
audit-logs: allow showing individual entries for audit log.
r2110
security: update lastactivity when on audit logs....
r2930 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()
audit-logs: introducing new audit logger for actions....
r1694
audit-logs: allow showing individual entries for audit log.
r2110 entry_id = user_log.entry_id or ''
log.info('AUDIT[%s]: Logging action: `%s` by user:id:%s[%s] ip:%s',
entry_id, action_name, user_id, username, ip_address)
audit-logs: introducing new audit logger for actions....
r1694 except Exception:
log.exception('AUDIT: failed to store audit log')
security: update lastactivity when on audit logs....
r2930
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")