##// END OF EJS Templates
audit-logs: fill in some default values for the expected action data.
marcink -
r1802:eabfaa9c default
parent child Browse files
Show More
@@ -1,231 +1,232 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 = {
32 'user.login.success': {},
33 'user.login.failure': {},
34 'user.logout': {},
32 'user.login.success': {'user_agent': ''},
33 'user.login.failure': {'user_agent': ''},
34 'user.logout': {'user_agent': ''},
35 35 'user.password.reset_request': {},
36 'user.push': {},
37 'user.pull': {},
36 'user.push': {'user_agent': '', 'commit_ids': []},
37 'user.pull': {'user_agent': ''},
38 38
39 'repo.create': {},
40 'repo.edit': {},
41 39 'user.create': {'data': {}},
42 40 'user.delete': {'old_data': {}},
43 41 'user.edit': {'old_data': {}},
44 42 'user.edit.permissions': {},
45 43 'user.edit.ip.add': {},
46 44 'user.edit.ip.delete': {},
47 45 'user.edit.token.add': {},
48 46 'user.edit.token.delete': {},
49 47 'user.edit.email.add': {},
50 48 'user.edit.email.delete': {},
51 49 'user.edit.password_reset.enabled': {},
52 50 'user.edit.password_reset.disabled': {},
53 51
52 'repo.create': {'data': {}},
53 'repo.edit': {'old_data': {}},
54 54 'repo.edit.permissions': {},
55 'repo.delete': {},
55 'repo.delete': {'old_data': {}},
56 56 'repo.commit.strip': {},
57 57 'repo.archive.download': {},
58 58
59 'repo_group.create': {},
60 'repo_group.edit': {},
59 'repo_group.create': {'data': {}},
60 'repo_group.edit': {'old_data': {}},
61 61 'repo_group.edit.permissions': {},
62 'repo_group.delete': {},
62 'repo_group.delete': {'old_data': {}},
63 63 }
64 64
65 65 SOURCE_WEB = 'source_web'
66 66 SOURCE_API = 'source_api'
67 67
68 68
69 69 class UserWrap(object):
70 70 """
71 71 Fake object used to imitate AuthUser
72 72 """
73 73
74 74 def __init__(self, user_id=None, username=None, ip_addr=None):
75 75 self.user_id = user_id
76 76 self.username = username
77 77 self.ip_addr = ip_addr
78 78
79 79
80 80 class RepoWrap(object):
81 81 """
82 82 Fake object used to imitate RepoObject that audit logger requires
83 83 """
84 84
85 85 def __init__(self, repo_id=None, repo_name=None):
86 86 self.repo_id = repo_id
87 87 self.repo_name = repo_name
88 88
89 89
90 90 def _store_log(action_name, action_data, user_id, username, user_data,
91 91 ip_address, repository_id, repository_name):
92 92 user_log = UserLog()
93 93 user_log.version = UserLog.VERSION_2
94 94
95 95 user_log.action = action_name
96 96 user_log.action_data = action_data
97 97
98 98 user_log.user_ip = ip_address
99 99
100 100 user_log.user_id = user_id
101 101 user_log.username = username
102 102 user_log.user_data = user_data
103 103
104 104 user_log.repository_id = repository_id
105 105 user_log.repository_name = repository_name
106 106
107 107 user_log.action_date = datetime.datetime.now()
108 108
109 109 log.info('AUDIT: Logging action: `%s` by user:id:%s[%s] ip:%s',
110 110 action_name, user_id, username, ip_address)
111 111
112 112 return user_log
113 113
114 114
115 115 def store_web(*args, **kwargs):
116 116 if 'action_data' not in kwargs:
117 117 kwargs['action_data'] = {}
118 118 kwargs['action_data'].update({
119 119 'source': SOURCE_WEB
120 120 })
121 121 return store(*args, **kwargs)
122 122
123 123
124 124 def store_api(*args, **kwargs):
125 125 if 'action_data' not in kwargs:
126 126 kwargs['action_data'] = {}
127 127 kwargs['action_data'].update({
128 128 'source': SOURCE_API
129 129 })
130 130 return store(*args, **kwargs)
131 131
132 132
133 133 def store(action, user, action_data=None, user_data=None, ip_addr=None,
134 134 repo=None, sa_session=None, commit=False):
135 135 """
136 136 Audit logger for various actions made by users, typically this
137 137 results in a call such::
138 138
139 139 from rhodecode.lib import audit_logger
140 140
141 141 audit_logger.store(
142 142 action='repo.edit', user=self._rhodecode_user)
143 143 audit_logger.store(
144 144 action='repo.delete', action_data={'repo_data': repo_data},
145 145 user=audit_logger.UserWrap(username='itried-login', ip_addr='8.8.8.8'))
146 146
147 147 # repo action
148 148 audit_logger.store(
149 149 action='repo.delete',
150 150 user=audit_logger.UserWrap(username='itried-login', ip_addr='8.8.8.8'),
151 151 repo=audit_logger.RepoWrap(repo_name='some-repo'))
152 152
153 153 # repo action, when we know and have the repository object already
154 154 audit_logger.store(
155 155 action='repo.delete',
156 156 action_data={'source': audit_logger.SOURCE_WEB, },
157 157 user=self._rhodecode_user,
158 158 repo=repo_object)
159 159
160 160 # alternative wrapper to the above
161 161 audit_logger.store_web(
162 162 action='repo.delete',
163 163 action_data={},
164 164 user=self._rhodecode_user,
165 165 repo=repo_object)
166 166
167 167 # without an user ?
168 168 audit_logger.store(
169 169 action='user.login.failure',
170 170 user=audit_logger.UserWrap(
171 171 username=self.request.params.get('username'),
172 172 ip_addr=self.request.remote_addr))
173 173
174 174 """
175 175 from rhodecode.lib.utils2 import safe_unicode
176 176 from rhodecode.lib.auth import AuthUser
177 177
178 if action not in ACTIONS:
179 raise ValueError('Action `{}` not in valid actions'.format(action))
178 action_spec = ACTIONS.get(action, None)
179 if action_spec is None:
180 raise ValueError('Action `{}` is not supported'.format(action))
180 181
181 182 if not sa_session:
182 183 sa_session = meta.Session()
183 184
184 185 try:
185 186 username = getattr(user, 'username', None)
186 187 if not username:
187 188 pass
188 189
189 190 user_id = getattr(user, 'user_id', None)
190 191 if not user_id:
191 192 # maybe we have username ? Try to figure user_id from username
192 193 if username:
193 194 user_id = getattr(
194 195 User.get_by_username(username), 'user_id', None)
195 196
196 197 ip_addr = ip_addr or getattr(user, 'ip_addr', None)
197 198 if not ip_addr:
198 199 pass
199 200
200 201 if not user_data:
201 202 # try to get this from the auth user
202 203 if isinstance(user, AuthUser):
203 204 user_data = {
204 205 'username': user.username,
205 206 'email': user.email,
206 207 }
207 208
208 209 repository_name = getattr(repo, 'repo_name', None)
209 210 repository_id = getattr(repo, 'repo_id', None)
210 211 if not repository_id:
211 212 # maybe we have repo_name ? Try to figure repo_id from repo_name
212 213 if repository_name:
213 214 repository_id = getattr(
214 215 Repository.get_by_repo_name(repository_name), 'repo_id', None)
215 216
216 217 user_log = _store_log(
217 218 action_name=safe_unicode(action),
218 219 action_data=action_data or {},
219 220 user_id=user_id,
220 221 username=username,
221 222 user_data=user_data or {},
222 223 ip_address=safe_unicode(ip_addr),
223 224 repository_id=repository_id,
224 225 repository_name=repository_name
225 226 )
226 227 sa_session.add(user_log)
227 228 if commit:
228 229 sa_session.commit()
229 230
230 231 except Exception:
231 232 log.exception('AUDIT: failed to store audit log')
General Comments 0
You need to be logged in to leave comments. Login now