##// END OF EJS Templates
my-account: use audit logs for email and token actions.
marcink -
r1820:0c30378e default
parent child Browse files
Show More
@@ -103,7 +103,7 b' class TestMyAccountAuthTokens(TestContro'
103
103
104 response = self.app.post(
104 response = self.app.post(
105 route_path('my_account_auth_tokens_delete'),
105 route_path('my_account_auth_tokens_delete'),
106 {'del_auth_token': keys[0].api_key, 'csrf_token': self.csrf_token})
106 {'del_auth_token': keys[0].user_api_key_id, 'csrf_token': self.csrf_token})
107 assert_session_flash(response, 'Auth token successfully deleted')
107 assert_session_flash(response, 'Auth token successfully deleted')
108
108
109 user = User.get(user_id)
109 user = User.get(user_id)
@@ -28,6 +28,7 b' from pyramid.view import view_config'
28 from rhodecode.apps._base import BaseAppView
28 from rhodecode.apps._base import BaseAppView
29 from rhodecode import forms
29 from rhodecode import forms
30 from rhodecode.lib import helpers as h
30 from rhodecode.lib import helpers as h
31 from rhodecode.lib import audit_logger
31 from rhodecode.lib.ext_json import json
32 from rhodecode.lib.ext_json import json
32 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
33 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
33 from rhodecode.lib.channelstream import channelstream_request, \
34 from rhodecode.lib.channelstream import channelstream_request, \
@@ -35,7 +36,7 b' from rhodecode.lib.channelstream import '
35 from rhodecode.lib.utils2 import safe_int, md5
36 from rhodecode.lib.utils2 import safe_int, md5
36 from rhodecode.model.auth_token import AuthTokenModel
37 from rhodecode.model.auth_token import AuthTokenModel
37 from rhodecode.model.db import (
38 from rhodecode.model.db import (
38 Repository, PullRequest, UserEmailMap, User, UserFollowing, joinedload)
39 Repository, UserEmailMap, UserApiKeys, UserFollowing, joinedload)
39 from rhodecode.model.meta import Session
40 from rhodecode.model.meta import Session
40 from rhodecode.model.scm import RepoList
41 from rhodecode.model.scm import RepoList
41 from rhodecode.model.user import UserModel
42 from rhodecode.model.user import UserModel
@@ -178,7 +179,13 b' class MyAccountView(BaseAppView):'
178
179
179 token = AuthTokenModel().create(
180 token = AuthTokenModel().create(
180 c.user.user_id, description, lifetime, role)
181 c.user.user_id, description, lifetime, role)
182 token_data = token.get_api_data()
183
181 self.maybe_attach_token_scope(token)
184 self.maybe_attach_token_scope(token)
185 audit_logger.store(
186 action='user.edit.token.add',
187 action_data={'data': {'token': token_data}},
188 user=self._rhodecode_user, )
182 Session().commit()
189 Session().commit()
183
190
184 h.flash(_("Auth token successfully created"), category='success')
191 h.flash(_("Auth token successfully created"), category='success')
@@ -196,7 +203,14 b' class MyAccountView(BaseAppView):'
196 del_auth_token = self.request.POST.get('del_auth_token')
203 del_auth_token = self.request.POST.get('del_auth_token')
197
204
198 if del_auth_token:
205 if del_auth_token:
206 token = UserApiKeys.get_or_404(del_auth_token, pyramid_exc=True)
207 token_data = token.get_api_data()
208
199 AuthTokenModel().delete(del_auth_token, c.user.user_id)
209 AuthTokenModel().delete(del_auth_token, c.user.user_id)
210 audit_logger.store(
211 action='user.edit.token.delete',
212 action_data={'data': {'token': token_data}},
213 user=self._rhodecode_user,)
200 Session().commit()
214 Session().commit()
201 h.flash(_("Auth token successfully deleted"), category='success')
215 h.flash(_("Auth token successfully deleted"), category='success')
202
216
@@ -230,6 +244,11 b' class MyAccountView(BaseAppView):'
230
244
231 try:
245 try:
232 UserModel().add_extra_email(c.user.user_id, email)
246 UserModel().add_extra_email(c.user.user_id, email)
247 audit_logger.store(
248 action='user.edit.email.add',
249 action_data={'data': {'email': email}},
250 user=self._rhodecode_user,)
251
233 Session().commit()
252 Session().commit()
234 h.flash(_("Added new email address `%s` for user account") % email,
253 h.flash(_("Added new email address `%s` for user account") % email,
235 category='success')
254 category='success')
@@ -253,9 +272,12 b' class MyAccountView(BaseAppView):'
253
272
254 del_email_id = self.request.POST.get('del_email_id')
273 del_email_id = self.request.POST.get('del_email_id')
255 if del_email_id:
274 if del_email_id:
256
275 email = UserEmailMap.get_or_404(del_email_id, pyramid_exc=True).email
257 UserModel().delete_extra_email(
276 UserModel().delete_extra_email(c.user.user_id, del_email_id)
258 c.user.user_id, del_email_id)
277 audit_logger.store(
278 action='user.edit.email.delete',
279 action_data={'data': {'email': email}},
280 user=self._rhodecode_user,)
259 Session().commit()
281 Session().commit()
260 h.flash(_("Email successfully deleted"),
282 h.flash(_("Email successfully deleted"),
261 category='success')
283 category='success')
@@ -59,20 +59,20 b' class AuthTokenModel(BaseModel):'
59
59
60 return new_auth_token
60 return new_auth_token
61
61
62 def delete(self, api_key, user=None):
62 def delete(self, auth_token_id, user=None):
63 """
63 """
64 Deletes given api_key, if user is set it also filters the object for
64 Deletes given api_key, if user is set it also filters the object for
65 deletion by given user.
65 deletion by given user.
66 """
66 """
67 api_key = UserApiKeys.query().filter(UserApiKeys.api_key == api_key)
67 auth_token = UserApiKeys.query().filter(
68 UserApiKeys.user_api_key_id == auth_token_id)
68
69
69 if user:
70 if user:
70 user = self._get_user(user)
71 user = self._get_user(user)
71 api_key = api_key.filter(UserApiKeys.user_id == user.user_id)
72 auth_token = auth_token.filter(UserApiKeys.user_id == user.user_id)
72
73 auth_token = auth_token.scalar()
73 api_key = api_key.scalar()
74 try:
74 try:
75 Session().delete(api_key)
75 Session().delete(auth_token)
76 except Exception:
76 except Exception:
77 log.error(traceback.format_exc())
77 log.error(traceback.format_exc())
78 raise
78 raise
@@ -1018,6 +1018,14 b' class UserApiKeys(Base, BaseModel):'
1018 }
1018 }
1019 return data
1019 return data
1020
1020
1021 def get_api_data(self, include_secrets=False):
1022 data = self.__json__()
1023 if include_secrets:
1024 return data
1025 else:
1026 data['auth_token'] = self.token_obfuscated
1027 return data
1028
1021 @property
1029 @property
1022 def expired(self):
1030 def expired(self):
1023 if self.expires == -1:
1031 if self.expires == -1:
@@ -1049,6 +1057,11 b' class UserApiKeys(Base, BaseModel):'
1049 def scope_humanized(self):
1057 def scope_humanized(self):
1050 return self._get_scope()
1058 return self._get_scope()
1051
1059
1060 @property
1061 def token_obfuscated(self):
1062 if self.api_key:
1063 return self.api_key[:4] + "****"
1064
1052
1065
1053 class UserEmailMap(Base, BaseModel):
1066 class UserEmailMap(Base, BaseModel):
1054 __tablename__ = 'user_email_map'
1067 __tablename__ = 'user_email_map'
@@ -43,9 +43,9 b''
43 </td>
43 </td>
44 <td class="td-action">
44 <td class="td-action">
45 ${h.secure_form(h.route_path('my_account_auth_tokens_delete'), method='post')}
45 ${h.secure_form(h.route_path('my_account_auth_tokens_delete'), method='post')}
46 ${h.hidden('del_auth_token',auth_token.api_key)}
46 ${h.hidden('del_auth_token', auth_token.user_api_key_id)}
47 <button class="btn btn-link btn-danger" type="submit"
47 <button class="btn btn-link btn-danger" type="submit"
48 onclick="return confirm('${_('Confirm to remove this auth token: %s') % auth_token.api_key}');">
48 onclick="return confirm('${_('Confirm to remove this auth token: %s') % auth_token.token_obfuscated}');">
49 ${_('Delete')}
49 ${_('Delete')}
50 </button>
50 </button>
51 ${h.end_form()}
51 ${h.end_form()}
General Comments 0
You need to be logged in to leave comments. Login now