##// END OF EJS Templates
audit-logs: updated action data attrbiutes.
marcink -
r1823:e27e4796 default
parent child Browse files
Show More
@@ -1,257 +1,257 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2017-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22 import datetime
23 23
24 24 from rhodecode.model import meta
25 25 from rhodecode.model.db import User, UserLog, Repository
26 26
27 27
28 28 log = logging.getLogger(__name__)
29 29
30 30 # action as key, and expected action_data as value
31 31 ACTIONS_V1 = {
32 32 'user.login.success': {'user_agent': ''},
33 33 'user.login.failure': {'user_agent': ''},
34 34 'user.logout': {'user_agent': ''},
35 35 'user.password.reset_request': {},
36 36 'user.push': {'user_agent': '', 'commit_ids': []},
37 37 'user.pull': {'user_agent': ''},
38 38
39 39 'user.create': {'data': {}},
40 40 'user.delete': {'old_data': {}},
41 41 'user.edit': {'old_data': {}},
42 42 'user.edit.permissions': {},
43 'user.edit.ip.add': {},
44 'user.edit.ip.delete': {},
45 'user.edit.token.add': {},
46 'user.edit.token.delete': {},
47 'user.edit.email.add': {},
48 'user.edit.email.delete': {},
43 'user.edit.ip.add': {'ip': {}, 'user': {}},
44 'user.edit.ip.delete': {'ip': {}, 'user': {}},
45 'user.edit.token.add': {'token': {}, 'user': {}},
46 'user.edit.token.delete': {'token': {}, 'user': {}},
47 'user.edit.email.add': {'email': ''},
48 'user.edit.email.delete': {'email': ''},
49 49 'user.edit.password_reset.enabled': {},
50 50 'user.edit.password_reset.disabled': {},
51 51
52 52 'user_group.create': {'data': {}},
53 53 'user_group.delete': {'old_data': {}},
54 54 'user_group.edit': {'old_data': {}},
55 55 'user_group.edit.permissions': {},
56 56 'user_group.edit.member.add': {},
57 57 'user_group.edit.member.delete': {},
58 58
59 59 'repo.create': {'data': {}},
60 60 'repo.fork': {'data': {}},
61 61 'repo.edit': {'old_data': {}},
62 62 'repo.edit.permissions': {},
63 63 'repo.delete': {'old_data': {}},
64 'repo.commit.strip': {},
65 'repo.archive.download': {},
66
64 'repo.commit.strip': {'commit_id': ''},
65 'repo.archive.download': {'user_agent': '', 'archive_name': '',
66 'archive_spec': '', 'archive_cached': ''},
67 67 'repo.pull_request.create': '',
68 68 'repo.pull_request.edit': '',
69 69 'repo.pull_request.delete': '',
70 70 'repo.pull_request.close': '',
71 71 'repo.pull_request.merge': '',
72 72 'repo.pull_request.vote': '',
73 73 'repo.pull_request.comment.create': '',
74 74 'repo.pull_request.comment.delete': '',
75 75
76 76 'repo.pull_request.reviewer.add': '',
77 77 'repo.pull_request.reviewer.delete': '',
78 78
79 79 'repo.commit.comment.create': '',
80 80 'repo.commit.comment.delete': '',
81 81 'repo.commit.vote': '',
82 82
83 83 'repo_group.create': {'data': {}},
84 84 'repo_group.edit': {'old_data': {}},
85 85 'repo_group.edit.permissions': {},
86 86 'repo_group.delete': {'old_data': {}},
87 87 }
88 88 ACTIONS = ACTIONS_V1
89 89
90 90 SOURCE_WEB = 'source_web'
91 91 SOURCE_API = 'source_api'
92 92
93 93
94 94 class UserWrap(object):
95 95 """
96 96 Fake object used to imitate AuthUser
97 97 """
98 98
99 99 def __init__(self, user_id=None, username=None, ip_addr=None):
100 100 self.user_id = user_id
101 101 self.username = username
102 102 self.ip_addr = ip_addr
103 103
104 104
105 105 class RepoWrap(object):
106 106 """
107 107 Fake object used to imitate RepoObject that audit logger requires
108 108 """
109 109
110 110 def __init__(self, repo_id=None, repo_name=None):
111 111 self.repo_id = repo_id
112 112 self.repo_name = repo_name
113 113
114 114
115 115 def _store_log(action_name, action_data, user_id, username, user_data,
116 116 ip_address, repository_id, repository_name):
117 117 user_log = UserLog()
118 118 user_log.version = UserLog.VERSION_2
119 119
120 120 user_log.action = action_name
121 121 user_log.action_data = action_data
122 122
123 123 user_log.user_ip = ip_address
124 124
125 125 user_log.user_id = user_id
126 126 user_log.username = username
127 127 user_log.user_data = user_data
128 128
129 129 user_log.repository_id = repository_id
130 130 user_log.repository_name = repository_name
131 131
132 132 user_log.action_date = datetime.datetime.now()
133 133
134 134 log.info('AUDIT: Logging action: `%s` by user:id:%s[%s] ip:%s',
135 135 action_name, user_id, username, ip_address)
136 136
137 137 return user_log
138 138
139 139
140 140 def store_web(*args, **kwargs):
141 141 if 'action_data' not in kwargs:
142 142 kwargs['action_data'] = {}
143 143 kwargs['action_data'].update({
144 144 'source': SOURCE_WEB
145 145 })
146 146 return store(*args, **kwargs)
147 147
148 148
149 149 def store_api(*args, **kwargs):
150 150 if 'action_data' not in kwargs:
151 151 kwargs['action_data'] = {}
152 152 kwargs['action_data'].update({
153 153 'source': SOURCE_API
154 154 })
155 155 return store(*args, **kwargs)
156 156
157 157
158 158 def store(action, user, action_data=None, user_data=None, ip_addr=None,
159 159 repo=None, sa_session=None, commit=False):
160 160 """
161 161 Audit logger for various actions made by users, typically this
162 162 results in a call such::
163 163
164 164 from rhodecode.lib import audit_logger
165 165
166 166 audit_logger.store(
167 167 action='repo.edit', user=self._rhodecode_user)
168 168 audit_logger.store(
169 169 action='repo.delete', action_data={'data': repo_data},
170 170 user=audit_logger.UserWrap(username='itried-login', ip_addr='8.8.8.8'))
171 171
172 172 # repo action
173 173 audit_logger.store(
174 174 action='repo.delete',
175 175 user=audit_logger.UserWrap(username='itried-login', ip_addr='8.8.8.8'),
176 176 repo=audit_logger.RepoWrap(repo_name='some-repo'))
177 177
178 178 # repo action, when we know and have the repository object already
179 179 audit_logger.store(
180 180 action='repo.delete',
181 181 action_data={'source': audit_logger.SOURCE_WEB, },
182 182 user=self._rhodecode_user,
183 183 repo=repo_object)
184 184
185 185 # alternative wrapper to the above
186 186 audit_logger.store_web(
187 187 action='repo.delete',
188 188 action_data={},
189 189 user=self._rhodecode_user,
190 190 repo=repo_object)
191 191
192 192 # without an user ?
193 193 audit_logger.store(
194 194 action='user.login.failure',
195 195 user=audit_logger.UserWrap(
196 196 username=self.request.params.get('username'),
197 197 ip_addr=self.request.remote_addr))
198 198
199 199 """
200 200 from rhodecode.lib.utils2 import safe_unicode
201 201 from rhodecode.lib.auth import AuthUser
202 202
203 203 action_spec = ACTIONS.get(action, None)
204 204 if action_spec is None:
205 205 raise ValueError('Action `{}` is not supported'.format(action))
206 206
207 207 if not sa_session:
208 208 sa_session = meta.Session()
209 209
210 210 try:
211 211 username = getattr(user, 'username', None)
212 212 if not username:
213 213 pass
214 214
215 215 user_id = getattr(user, 'user_id', None)
216 216 if not user_id:
217 217 # maybe we have username ? Try to figure user_id from username
218 218 if username:
219 219 user_id = getattr(
220 220 User.get_by_username(username), 'user_id', None)
221 221
222 222 ip_addr = ip_addr or getattr(user, 'ip_addr', None)
223 223 if not ip_addr:
224 224 pass
225 225
226 226 if not user_data:
227 227 # try to get this from the auth user
228 228 if isinstance(user, AuthUser):
229 229 user_data = {
230 230 'username': user.username,
231 231 'email': user.email,
232 232 }
233 233
234 234 repository_name = getattr(repo, 'repo_name', None)
235 235 repository_id = getattr(repo, 'repo_id', None)
236 236 if not repository_id:
237 237 # maybe we have repo_name ? Try to figure repo_id from repo_name
238 238 if repository_name:
239 239 repository_id = getattr(
240 240 Repository.get_by_repo_name(repository_name), 'repo_id', None)
241 241
242 242 user_log = _store_log(
243 243 action_name=safe_unicode(action),
244 244 action_data=action_data or {},
245 245 user_id=user_id,
246 246 username=username,
247 247 user_data=user_data or {},
248 248 ip_address=safe_unicode(ip_addr),
249 249 repository_id=repository_id,
250 250 repository_name=repository_name
251 251 )
252 252 sa_session.add(user_log)
253 253 if commit:
254 254 sa_session.commit()
255 255
256 256 except Exception:
257 257 log.exception('AUDIT: failed to store audit log')
General Comments 0
You need to be logged in to leave comments. Login now