##// END OF EJS Templates
audit-logs: introducing new audit logger for actions....
marcink -
r1694:e5ba2a61 default
parent child Browse files
Show More
@@ -0,0 +1,138 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import logging
22 import datetime
23
24 from rhodecode.model import meta
25 from rhodecode.model.db import User, UserLog
26
27
28 log = logging.getLogger(__name__)
29
30
31 ACTIONS = {
32 'repo.add': {},
33 'repo.edit': {},
34 }
35
36
37 class UserWrap(object):
38 """
39 Fake object used to imitate AuthUser
40 """
41
42 def __init__(self, user_id=None, username=None, ip_addr=None):
43 self.user_id = user_id
44 self.username = username
45 self.ip_addr = ip_addr
46
47
48 def _store_log(action_name, action_data, user_id, username, user_data,
49 ip_address, repository_id, repository_name):
50 user_log = UserLog()
51 user_log.version = UserLog.VERSION_2
52
53 user_log.action = action_name
54 user_log.action_data = action_data
55
56 user_log.user_ip = ip_address
57
58 user_log.user_id = user_id
59 user_log.username = username
60 user_log.user_data = user_data
61
62 user_log.repository_id = repository_id
63 user_log.repository_name = repository_name
64
65 user_log.action_date = datetime.datetime.now()
66
67 log.info('AUDIT: Logging action: `%s` by user:id:%s[%s] ip:%s',
68 action_name, user_id, username, ip_address)
69
70 return user_log
71
72
73 def store(
74 action, user, action_data=None, user_data=None, ip_addr=None,
75 repo=None, sa_session=None, commit=False):
76 """
77 Audit logger for various actions made by users, typically this results in a call such::
78
79 from rhodecode.lib import audit_logger
80
81 audit_logger.store(action='repo.edit', user=self._rhodecode_user)
82 audit_logger.store(action='repo.delete', user=audit_logger.UserWrap(username='itried-to-login', ip_addr='8.8.8.8'))
83
84 # without an user ?
85 audit_user = audit_logger.UserWrap(
86 username=self.request.params.get('username'),
87 ip_addr=self.request.remote_addr)
88 audit_logger.store(action='user.login.failure', user=audit_user)
89 """
90 from rhodecode.lib.utils2 import safe_unicode
91 from rhodecode.lib.auth import AuthUser
92
93 if action not in ACTIONS:
94 raise ValueError('Action `{}` not in valid actions'.format(action))
95
96 if not sa_session:
97 sa_session = meta.Session()
98
99 try:
100 username = getattr(user, 'username', None)
101 if not username:
102 pass
103
104 user_id = getattr(user, 'user_id', None)
105 if not user_id:
106 # maybe we have username ? Try to figure user_id from username
107 if username:
108 user_id = getattr(
109 User.get_by_username(username), 'user_id', None)
110
111 ip_addr = ip_addr or getattr(user, 'ip_addr', None)
112 if not ip_addr:
113 pass
114
115 if not user_data:
116 # try to get this from the auth user
117 if isinstance(user, AuthUser):
118 user_data = {}
119
120 repository_id = getattr(repo, 'repo_id', None)
121 repository_name = getattr(repo, 'repo_name', None)
122
123 user_log = _store_log(
124 action_name=safe_unicode(action),
125 action_data=action_data or {},
126 user_id=user_id,
127 username=username,
128 user_data=user_data or {},
129 ip_address=safe_unicode(ip_addr),
130 repository_id=repository_id,
131 repository_name=repository_name
132 )
133 sa_session.add(user_log)
134 if commit:
135 sa_session.commit()
136
137 except Exception:
138 log.exception('AUDIT: failed to store audit log')
@@ -1098,6 +1098,10 b' class UserLog(Base, BaseModel):'
1098 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1098 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1099 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1099 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1100 )
1100 )
1101 VERSION_1 = 'v1'
1102 VERSION_2 = 'v2'
1103 VERSIONS = [VERSION_1, VERSION_2]
1104
1101 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1105 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1102 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1106 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1103 username = Column("username", String(255), nullable=True, unique=None, default=None)
1107 username = Column("username", String(255), nullable=True, unique=None, default=None)
@@ -1107,7 +1111,7 b' class UserLog(Base, BaseModel):'
1107 action = Column("action", Text().with_variant(Text(1200000), 'mysql'), nullable=True, unique=None, default=None)
1111 action = Column("action", Text().with_variant(Text(1200000), 'mysql'), nullable=True, unique=None, default=None)
1108 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
1112 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
1109
1113
1110 version = Column("version", String(255), nullable=True, default='v1')
1114 version = Column("version", String(255), nullable=True, default=VERSION_1)
1111 user_data = Column('user_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
1115 user_data = Column('user_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
1112 action_data = Column('action_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
1116 action_data = Column('action_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
1113
1117
General Comments 0
You need to be logged in to leave comments. Login now