Show More
@@ -37,7 +37,7 b' from rhodecode.authentication.interface ' | |||||
37 | from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase |
|
37 | from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase | |
38 | from rhodecode.lib import caches |
|
38 | from rhodecode.lib import caches | |
39 | from rhodecode.lib.auth import PasswordGenerator, _RhodeCodeCryptoBCrypt |
|
39 | from rhodecode.lib.auth import PasswordGenerator, _RhodeCodeCryptoBCrypt | |
40 |
from rhodecode.lib.utils2 import |
|
40 | from rhodecode.lib.utils2 import safe_int | |
41 | from rhodecode.lib.utils2 import safe_str |
|
41 | from rhodecode.lib.utils2 import safe_str | |
42 | from rhodecode.model.db import User |
|
42 | from rhodecode.model.db import User | |
43 | from rhodecode.model.meta import Session |
|
43 | from rhodecode.model.meta import Session | |
@@ -423,11 +423,14 b' class RhodeCodeAuthPluginBase(object):' | |||||
423 | """ |
|
423 | """ | |
424 | auth = self.auth(userobj, username, passwd, settings, **kwargs) |
|
424 | auth = self.auth(userobj, username, passwd, settings, **kwargs) | |
425 | if auth: |
|
425 | if auth: | |
|
426 | auth['_plugin'] = self.name | |||
|
427 | auth['_ttl_cache'] = self.get_ttl_cache(settings) | |||
426 | # check if hash should be migrated ? |
|
428 | # check if hash should be migrated ? | |
427 | new_hash = auth.get('_hash_migrate') |
|
429 | new_hash = auth.get('_hash_migrate') | |
428 | if new_hash: |
|
430 | if new_hash: | |
429 | self._migrate_hash_to_bcrypt(username, passwd, new_hash) |
|
431 | self._migrate_hash_to_bcrypt(username, passwd, new_hash) | |
430 | return self._validate_auth_return(auth) |
|
432 | return self._validate_auth_return(auth) | |
|
433 | ||||
431 | return auth |
|
434 | return auth | |
432 |
|
435 | |||
433 | def _migrate_hash_to_bcrypt(self, username, password, new_hash): |
|
436 | def _migrate_hash_to_bcrypt(self, username, password, new_hash): | |
@@ -450,6 +453,19 b' class RhodeCodeAuthPluginBase(object):' | |||||
450 | raise Exception('Missing %s attribute from returned data' % k) |
|
453 | raise Exception('Missing %s attribute from returned data' % k) | |
451 | return ret |
|
454 | return ret | |
452 |
|
455 | |||
|
456 | def get_ttl_cache(self, settings=None): | |||
|
457 | plugin_settings = settings or self.get_settings() | |||
|
458 | cache_ttl = 0 | |||
|
459 | ||||
|
460 | if isinstance(self.AUTH_CACHE_TTL, (int, long)): | |||
|
461 | # plugin cache set inside is more important than the settings value | |||
|
462 | cache_ttl = self.AUTH_CACHE_TTL | |||
|
463 | elif plugin_settings.get('cache_ttl'): | |||
|
464 | cache_ttl = safe_int(plugin_settings.get('cache_ttl'), 0) | |||
|
465 | ||||
|
466 | plugin_cache_active = bool(cache_ttl and cache_ttl > 0) | |||
|
467 | return plugin_cache_active, cache_ttl | |||
|
468 | ||||
453 |
|
469 | |||
454 | class RhodeCodeExternalAuthPlugin(RhodeCodeAuthPluginBase): |
|
470 | class RhodeCodeExternalAuthPlugin(RhodeCodeAuthPluginBase): | |
455 |
|
471 | |||
@@ -578,6 +594,11 b' def get_auth_cache_manager(custom_ttl=No' | |||||
578 | 'auth_plugins', 'rhodecode.authentication', custom_ttl) |
|
594 | 'auth_plugins', 'rhodecode.authentication', custom_ttl) | |
579 |
|
595 | |||
580 |
|
596 | |||
|
597 | def get_perms_cache_manager(custom_ttl=None): | |||
|
598 | return caches.get_cache_manager( | |||
|
599 | 'auth_plugins', 'rhodecode.permissions', custom_ttl) | |||
|
600 | ||||
|
601 | ||||
581 | def authenticate(username, password, environ=None, auth_type=None, |
|
602 | def authenticate(username, password, environ=None, auth_type=None, | |
582 | skip_missing=False, registry=None, acl_repo_name=None): |
|
603 | skip_missing=False, registry=None, acl_repo_name=None): | |
583 | """ |
|
604 | """ | |
@@ -633,25 +654,19 b' def authenticate(username, password, env' | |||||
633 | log.info('Authenticating user `%s` using %s plugin', |
|
654 | log.info('Authenticating user `%s` using %s plugin', | |
634 | display_user, plugin.get_id()) |
|
655 | display_user, plugin.get_id()) | |
635 |
|
656 | |||
636 | _cache_ttl = 0 |
|
657 | plugin_cache_active, cache_ttl = plugin.get_ttl_cache(plugin_settings) | |
637 |
|
||||
638 | if isinstance(plugin.AUTH_CACHE_TTL, (int, long)): |
|
|||
639 | # plugin cache set inside is more important than the settings value |
|
|||
640 | _cache_ttl = plugin.AUTH_CACHE_TTL |
|
|||
641 | elif plugin_settings.get('cache_ttl'): |
|
|||
642 | _cache_ttl = safe_int(plugin_settings.get('cache_ttl'), 0) |
|
|||
643 |
|
||||
644 | plugin_cache_active = bool(_cache_ttl and _cache_ttl > 0) |
|
|||
645 |
|
658 | |||
646 | # get instance of cache manager configured for a namespace |
|
659 | # get instance of cache manager configured for a namespace | |
647 |
cache_manager = get_auth_cache_manager(custom_ttl= |
|
660 | cache_manager = get_auth_cache_manager(custom_ttl=cache_ttl) | |
648 |
|
661 | |||
649 | log.debug('AUTH_CACHE_TTL for plugin `%s` active: %s (TTL: %s)', |
|
662 | log.debug('AUTH_CACHE_TTL for plugin `%s` active: %s (TTL: %s)', | |
650 |
plugin.get_id(), plugin_cache_active, |
|
663 | plugin.get_id(), plugin_cache_active, cache_ttl) | |
651 |
|
664 | |||
652 | # for environ based password can be empty, but then the validation is |
|
665 | # for environ based password can be empty, but then the validation is | |
653 | # on the server that fills in the env data needed for authentication |
|
666 | # on the server that fills in the env data needed for authentication | |
654 | _password_hash = md5_safe(plugin.name + username + (password or '')) |
|
667 | ||
|
668 | _password_hash = caches.compute_key_from_params( | |||
|
669 | plugin.name, username, (password or '')) | |||
655 |
|
670 | |||
656 | # _authenticate is a wrapper for .auth() method of plugin. |
|
671 | # _authenticate is a wrapper for .auth() method of plugin. | |
657 | # it checks if .auth() sends proper data. |
|
672 | # it checks if .auth() sends proper data. | |
@@ -667,11 +682,13 b' def authenticate(username, password, env' | |||||
667 | This function is used internally in Cache of Beaker to calculate |
|
682 | This function is used internally in Cache of Beaker to calculate | |
668 | Results |
|
683 | Results | |
669 | """ |
|
684 | """ | |
|
685 | log.debug('auth: calculating password access now...') | |||
670 | return plugin._authenticate( |
|
686 | return plugin._authenticate( | |
671 | user, username, password, plugin_settings, |
|
687 | user, username, password, plugin_settings, | |
672 | environ=environ or {}) |
|
688 | environ=environ or {}) | |
673 |
|
689 | |||
674 | if plugin_cache_active: |
|
690 | if plugin_cache_active: | |
|
691 | log.debug('Trying to fetch cached auth by %s', _password_hash[:6]) | |||
675 | plugin_user = cache_manager.get( |
|
692 | plugin_user = cache_manager.get( | |
676 | _password_hash, createfunc=auth_func) |
|
693 | _password_hash, createfunc=auth_func) | |
677 | else: |
|
694 | else: | |
@@ -680,7 +697,7 b' def authenticate(username, password, env' | |||||
680 | auth_time = time.time() - start |
|
697 | auth_time = time.time() - start | |
681 | log.debug('Authentication for plugin `%s` completed in %.3fs, ' |
|
698 | log.debug('Authentication for plugin `%s` completed in %.3fs, ' | |
682 | 'expiration time of fetched cache %.1fs.', |
|
699 | 'expiration time of fetched cache %.1fs.', | |
683 |
plugin.get_id(), auth_time, |
|
700 | plugin.get_id(), auth_time, cache_ttl) | |
684 |
|
701 | |||
685 | log.debug('PLUGIN USER DATA: %s', plugin_user) |
|
702 | log.debug('PLUGIN USER DATA: %s', plugin_user) | |
686 |
|
703 | |||
@@ -690,6 +707,8 b' def authenticate(username, password, env' | |||||
690 | # we failed to Auth because .auth() method didn't return proper user |
|
707 | # we failed to Auth because .auth() method didn't return proper user | |
691 | log.debug("User `%s` failed to authenticate against %s", |
|
708 | log.debug("User `%s` failed to authenticate against %s", | |
692 | display_user, plugin.get_id()) |
|
709 | display_user, plugin.get_id()) | |
|
710 | ||||
|
711 | # case when we failed to authenticate against all defined plugins | |||
693 | return None |
|
712 | return None | |
694 |
|
713 | |||
695 |
|
714 |
@@ -40,11 +40,10 b' class AuthnPluginSettingsSchemaBase(cola' | |||||
40 | cache_ttl = colander.SchemaNode( |
|
40 | cache_ttl = colander.SchemaNode( | |
41 | colander.Int(), |
|
41 | colander.Int(), | |
42 | default=0, |
|
42 | default=0, | |
43 |
description=_('Amount of seconds to cache the authentication |
|
43 | description=_('Amount of seconds to cache the authentication and ' | |
44 | 'call for this plugin. \n' |
|
44 | 'permissions check response call for this plugin. \n' | |
45 |
'Useful for |
|
45 | 'Useful for expensive calls like LDAP to improve the ' | |
46 |
'performance of the |
|
46 | 'performance of the system (0 means disabled).'), | |
47 | '(0 means disabled).'), |
|
|||
48 | missing=0, |
|
47 | missing=0, | |
49 | title=_('Auth Cache TTL'), |
|
48 | title=_('Auth Cache TTL'), | |
50 | validator=colander.Range(min=0, max=None), |
|
49 | validator=colander.Range(min=0, max=None), |
@@ -277,10 +277,11 b' class BasicAuth(AuthBasicAuthenticator):' | |||||
277 | _parts = auth.split(':', 1) |
|
277 | _parts = auth.split(':', 1) | |
278 | if len(_parts) == 2: |
|
278 | if len(_parts) == 2: | |
279 | username, password = _parts |
|
279 | username, password = _parts | |
280 |
|
|
280 | auth_data = self.authfunc( | |
281 | username, password, environ, VCS_TYPE, |
|
281 | username, password, environ, VCS_TYPE, | |
282 |
registry=self.registry, acl_repo_name=self.acl_repo_name) |
|
282 | registry=self.registry, acl_repo_name=self.acl_repo_name) | |
283 | return username |
|
283 | if auth_data: | |
|
284 | return {'username': username, 'auth_data': auth_data} | |||
284 | if username and password: |
|
285 | if username and password: | |
285 | # we mark that we actually executed authentication once, at |
|
286 | # we mark that we actually executed authentication once, at | |
286 | # that point we can use the alternative auth code |
|
287 | # that point we can use the alternative auth code |
@@ -24,17 +24,20 b" It's implemented with basic auth functio" | |||||
24 | """ |
|
24 | """ | |
25 |
|
25 | |||
26 | import os |
|
26 | import os | |
|
27 | import re | |||
27 | import logging |
|
28 | import logging | |
28 | import importlib |
|
29 | import importlib | |
29 | import re |
|
|||
30 | from functools import wraps |
|
30 | from functools import wraps | |
31 |
|
31 | |||
|
32 | import time | |||
32 | from paste.httpheaders import REMOTE_USER, AUTH_TYPE |
|
33 | from paste.httpheaders import REMOTE_USER, AUTH_TYPE | |
33 | from webob.exc import ( |
|
34 | from webob.exc import ( | |
34 | HTTPNotFound, HTTPForbidden, HTTPNotAcceptable, HTTPInternalServerError) |
|
35 | HTTPNotFound, HTTPForbidden, HTTPNotAcceptable, HTTPInternalServerError) | |
35 |
|
36 | |||
36 | import rhodecode |
|
37 | import rhodecode | |
37 |
from rhodecode.authentication.base import |
|
38 | from rhodecode.authentication.base import ( | |
|
39 | authenticate, get_perms_cache_manager, VCS_TYPE) | |||
|
40 | from rhodecode.lib import caches | |||
38 | from rhodecode.lib.auth import AuthUser, HasPermissionAnyMiddleware |
|
41 | from rhodecode.lib.auth import AuthUser, HasPermissionAnyMiddleware | |
39 | from rhodecode.lib.base import ( |
|
42 | from rhodecode.lib.base import ( | |
40 | BasicAuth, get_ip_addr, get_user_agent, vcs_operation_context) |
|
43 | BasicAuth, get_ip_addr, get_user_agent, vcs_operation_context) | |
@@ -44,8 +47,7 b' from rhodecode.lib.exceptions import (' | |||||
44 | from rhodecode.lib.hooks_daemon import prepare_callback_daemon |
|
47 | from rhodecode.lib.hooks_daemon import prepare_callback_daemon | |
45 | from rhodecode.lib.middleware import appenlight |
|
48 | from rhodecode.lib.middleware import appenlight | |
46 | from rhodecode.lib.middleware.utils import scm_app_http |
|
49 | from rhodecode.lib.middleware.utils import scm_app_http | |
47 |
from rhodecode.lib.utils import |
|
50 | from rhodecode.lib.utils import is_valid_repo, SLUG_RE | |
48 | is_valid_repo, get_rhodecode_base_path, SLUG_RE) |
|
|||
49 | from rhodecode.lib.utils2 import safe_str, fix_PATH, str2bool, safe_unicode |
|
51 | from rhodecode.lib.utils2 import safe_str, fix_PATH, str2bool, safe_unicode | |
50 | from rhodecode.lib.vcs.conf import settings as vcs_settings |
|
52 | from rhodecode.lib.vcs.conf import settings as vcs_settings | |
51 | from rhodecode.lib.vcs.backends import base |
|
53 | from rhodecode.lib.vcs.backends import base | |
@@ -242,40 +244,81 b' class SimpleVCS(object):' | |||||
242 | def is_shadow_repo_dir(self): |
|
244 | def is_shadow_repo_dir(self): | |
243 | return os.path.isdir(self.vcs_repo_name) |
|
245 | return os.path.isdir(self.vcs_repo_name) | |
244 |
|
246 | |||
245 |
def _check_permission(self, action, user, repo_name, ip_addr=None |
|
247 | def _check_permission(self, action, user, repo_name, ip_addr=None, | |
|
248 | plugin_id='', plugin_cache_active=False, cache_ttl=0): | |||
246 | """ |
|
249 | """ | |
247 | Checks permissions using action (push/pull) user and repository |
|
250 | Checks permissions using action (push/pull) user and repository | |
248 | name |
|
251 | name. If plugin_cache and ttl is set it will use the plugin which | |
|
252 | authenticated the user to store the cached permissions result for N | |||
|
253 | amount of seconds as in cache_ttl | |||
249 |
|
254 | |||
250 | :param action: push or pull action |
|
255 | :param action: push or pull action | |
251 | :param user: user instance |
|
256 | :param user: user instance | |
252 | :param repo_name: repository name |
|
257 | :param repo_name: repository name | |
253 | """ |
|
258 | """ | |
|
259 | ||||
|
260 | # get instance of cache manager configured for a namespace | |||
|
261 | cache_manager = get_perms_cache_manager(custom_ttl=cache_ttl) | |||
|
262 | log.debug('AUTH_CACHE_TTL for permissions `%s` active: %s (TTL: %s)', | |||
|
263 | plugin_id, plugin_cache_active, cache_ttl) | |||
|
264 | ||||
|
265 | # for environ based password can be empty, but then the validation is | |||
|
266 | # on the server that fills in the env data needed for authentication | |||
|
267 | _perm_calc_hash = caches.compute_key_from_params( | |||
|
268 | plugin_id, action, user.user_id, repo_name, ip_addr) | |||
|
269 | ||||
|
270 | # _authenticate is a wrapper for .auth() method of plugin. | |||
|
271 | # it checks if .auth() sends proper data. | |||
|
272 | # For RhodeCodeExternalAuthPlugin it also maps users to | |||
|
273 | # Database and maps the attributes returned from .auth() | |||
|
274 | # to RhodeCode database. If this function returns data | |||
|
275 | # then auth is correct. | |||
|
276 | start = time.time() | |||
|
277 | log.debug('Running plugin `%s` permissions check', plugin_id) | |||
|
278 | ||||
|
279 | def perm_func(): | |||
|
280 | """ | |||
|
281 | This function is used internally in Cache of Beaker to calculate | |||
|
282 | Results | |||
|
283 | """ | |||
|
284 | log.debug('auth: calculating permission access now...') | |||
254 | # check IP |
|
285 | # check IP | |
255 | inherit = user.inherit_default_permissions |
|
286 | inherit = user.inherit_default_permissions | |
256 |
ip_allowed = AuthUser.check_ip_allowed( |
|
287 | ip_allowed = AuthUser.check_ip_allowed( | |
257 |
|
|
288 | user.user_id, ip_addr, inherit_from_default=inherit) | |
258 | if ip_allowed: |
|
289 | if ip_allowed: | |
259 | log.info('Access for IP:%s allowed', ip_addr) |
|
290 | log.info('Access for IP:%s allowed', ip_addr) | |
260 | else: |
|
291 | else: | |
261 | return False |
|
292 | return False | |
262 |
|
293 | |||
263 | if action == 'push': |
|
294 | if action == 'push': | |
264 | if not HasPermissionAnyMiddleware('repository.write', |
|
295 | perms = ('repository.write', 'repository.admin') | |
265 | 'repository.admin')(user, |
|
296 | if not HasPermissionAnyMiddleware(*perms)(user, repo_name): | |
266 | repo_name): |
|
|||
267 | return False |
|
297 | return False | |
268 |
|
298 | |||
269 | else: |
|
299 | else: | |
270 | # any other action need at least read permission |
|
300 | # any other action need at least read permission | |
271 | if not HasPermissionAnyMiddleware('repository.read', |
|
301 | perms = ( | |
272 | 'repository.write', |
|
302 | 'repository.read', 'repository.write', 'repository.admin') | |
273 | 'repository.admin')(user, |
|
303 | if not HasPermissionAnyMiddleware(*perms)(user, repo_name): | |
274 | repo_name): |
|
|||
275 | return False |
|
304 | return False | |
276 |
|
305 | |||
277 | return True |
|
306 | return True | |
278 |
|
307 | |||
|
308 | if plugin_cache_active: | |||
|
309 | log.debug('Trying to fetch cached perms by %s', _perm_calc_hash[:6]) | |||
|
310 | perm_result = cache_manager.get( | |||
|
311 | _perm_calc_hash, createfunc=perm_func) | |||
|
312 | else: | |||
|
313 | perm_result = perm_func() | |||
|
314 | ||||
|
315 | auth_time = time.time() - start | |||
|
316 | log.debug('Permissions for plugin `%s` completed in %.3fs, ' | |||
|
317 | 'expiration time of fetched cache %.1fs.', | |||
|
318 | plugin_id, auth_time, cache_ttl) | |||
|
319 | ||||
|
320 | return perm_result | |||
|
321 | ||||
279 | def _check_ssl(self, environ, start_response): |
|
322 | def _check_ssl(self, environ, start_response): | |
280 | """ |
|
323 | """ | |
281 | Checks the SSL check flag and returns False if SSL is not present |
|
324 | Checks the SSL check flag and returns False if SSL is not present | |
@@ -376,26 +419,41 b' class SimpleVCS(object):' | |||||
376 | if pre_auth and pre_auth.get('username'): |
|
419 | if pre_auth and pre_auth.get('username'): | |
377 | username = pre_auth['username'] |
|
420 | username = pre_auth['username'] | |
378 | log.debug('PRE-AUTH got %s as username', username) |
|
421 | log.debug('PRE-AUTH got %s as username', username) | |
|
422 | if pre_auth: | |||
|
423 | log.debug('PRE-AUTH successful from %s', | |||
|
424 | pre_auth.get('auth_data', {}).get('_plugin')) | |||
379 |
|
425 | |||
380 | # If not authenticated by the container, running basic auth |
|
426 | # If not authenticated by the container, running basic auth | |
381 | # before inject the calling repo_name for special scope checks |
|
427 | # before inject the calling repo_name for special scope checks | |
382 | self.authenticate.acl_repo_name = self.acl_repo_name |
|
428 | self.authenticate.acl_repo_name = self.acl_repo_name | |
|
429 | ||||
|
430 | plugin_cache_active, cache_ttl = False, 0 | |||
|
431 | plugin = None | |||
383 | if not username: |
|
432 | if not username: | |
384 | self.authenticate.realm = self.authenticate.get_rc_realm() |
|
433 | self.authenticate.realm = self.authenticate.get_rc_realm() | |
385 |
|
434 | |||
386 | try: |
|
435 | try: | |
387 | result = self.authenticate(environ) |
|
436 | auth_result = self.authenticate(environ) | |
388 | except (UserCreationError, NotAllowedToCreateUserError) as e: |
|
437 | except (UserCreationError, NotAllowedToCreateUserError) as e: | |
389 | log.error(e) |
|
438 | log.error(e) | |
390 | reason = safe_str(e) |
|
439 | reason = safe_str(e) | |
391 | return HTTPNotAcceptable(reason)(environ, start_response) |
|
440 | return HTTPNotAcceptable(reason)(environ, start_response) | |
392 |
|
441 | |||
393 |
if isinstance(result, |
|
442 | if isinstance(auth_result, dict): | |
394 | AUTH_TYPE.update(environ, 'basic') |
|
443 | AUTH_TYPE.update(environ, 'basic') | |
395 | REMOTE_USER.update(environ, result) |
|
444 | REMOTE_USER.update(environ, auth_result['username']) | |
396 | username = result |
|
445 | username = auth_result['username'] | |
|
446 | plugin = auth_result.get('auth_data', {}).get('_plugin') | |||
|
447 | log.info( | |||
|
448 | 'MAIN-AUTH successful for user `%s` from %s plugin', | |||
|
449 | username, plugin) | |||
|
450 | ||||
|
451 | plugin_cache_active, cache_ttl = auth_result.get( | |||
|
452 | 'auth_data', {}).get('_ttl_cache') or (False, 0) | |||
397 | else: |
|
453 | else: | |
398 |
return result.wsgi_application( |
|
454 | return auth_result.wsgi_application( | |
|
455 | environ, start_response) | |||
|
456 | ||||
399 |
|
457 | |||
400 | # ============================================================== |
|
458 | # ============================================================== | |
401 | # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME |
|
459 | # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME | |
@@ -417,12 +475,13 b' class SimpleVCS(object):' | |||||
417 |
|
475 | |||
418 | # check permissions for this repository |
|
476 | # check permissions for this repository | |
419 | perm = self._check_permission( |
|
477 | perm = self._check_permission( | |
420 |
action, user, self.acl_repo_name, ip_addr |
|
478 | action, user, self.acl_repo_name, ip_addr, | |
|
479 | plugin, plugin_cache_active, cache_ttl) | |||
421 | if not perm: |
|
480 | if not perm: | |
422 | return HTTPForbidden()(environ, start_response) |
|
481 | return HTTPForbidden()(environ, start_response) | |
423 |
|
482 | |||
424 | # extras are injected into UI object and later available |
|
483 | # extras are injected into UI object and later available | |
425 |
# in hooks executed by |
|
484 | # in hooks executed by RhodeCode | |
426 | check_locking = _should_check_locking(environ.get('QUERY_STRING')) |
|
485 | check_locking = _should_check_locking(environ.get('QUERY_STRING')) | |
427 | extras = vcs_operation_context( |
|
486 | extras = vcs_operation_context( | |
428 | environ, repo_name=self.acl_repo_name, username=username, |
|
487 | environ, repo_name=self.acl_repo_name, username=username, |
@@ -918,7 +918,7 b' class User(Base, BaseModel):' | |||||
918 | """Update user lastactivity""" |
|
918 | """Update user lastactivity""" | |
919 | self.last_activity = datetime.datetime.now() |
|
919 | self.last_activity = datetime.datetime.now() | |
920 | Session().add(self) |
|
920 | Session().add(self) | |
921 | log.debug('updated user %s lastactivity', self.username) |
|
921 | log.debug('updated user `%s` last activity', self.username) | |
922 |
|
922 | |||
923 | def update_password(self, new_password): |
|
923 | def update_password(self, new_password): | |
924 | from rhodecode.lib.auth import get_crypt_password |
|
924 | from rhodecode.lib.auth import get_crypt_password |
@@ -27,8 +27,13 b' from rhodecode.authentication.plugins.au' | |||||
27 | from rhodecode.model import db |
|
27 | from rhodecode.model import db | |
28 |
|
28 | |||
29 |
|
29 | |||
|
30 | class TestAuthPlugin(RhodeCodeAuthPluginBase): | |||
|
31 | ||||
|
32 | def name(self): | |||
|
33 | return 'stub_auth' | |||
|
34 | ||||
30 | def test_authenticate_returns_from_auth(stub_auth_data): |
|
35 | def test_authenticate_returns_from_auth(stub_auth_data): | |
31 |
plugin = |
|
36 | plugin = TestAuthPlugin('stub_id') | |
32 | with mock.patch.object(plugin, 'auth') as auth_mock: |
|
37 | with mock.patch.object(plugin, 'auth') as auth_mock: | |
33 | auth_mock.return_value = stub_auth_data |
|
38 | auth_mock.return_value = stub_auth_data | |
34 | result = plugin._authenticate(mock.Mock(), 'test', 'password', {}) |
|
39 | result = plugin._authenticate(mock.Mock(), 'test', 'password', {}) | |
@@ -37,7 +42,7 b' def test_authenticate_returns_from_auth(' | |||||
37 |
|
42 | |||
38 | def test_authenticate_returns_empty_auth_data(): |
|
43 | def test_authenticate_returns_empty_auth_data(): | |
39 | auth_data = {} |
|
44 | auth_data = {} | |
40 |
plugin = |
|
45 | plugin = TestAuthPlugin('stub_id') | |
41 | with mock.patch.object(plugin, 'auth') as auth_mock: |
|
46 | with mock.patch.object(plugin, 'auth') as auth_mock: | |
42 | auth_mock.return_value = auth_data |
|
47 | auth_mock.return_value = auth_data | |
43 | result = plugin._authenticate(mock.Mock(), 'test', 'password', {}) |
|
48 | result = plugin._authenticate(mock.Mock(), 'test', 'password', {}) | |
@@ -46,7 +51,7 b' def test_authenticate_returns_empty_auth' | |||||
46 |
|
51 | |||
47 | def test_authenticate_skips_hash_migration_if_mismatch(stub_auth_data): |
|
52 | def test_authenticate_skips_hash_migration_if_mismatch(stub_auth_data): | |
48 | stub_auth_data['_hash_migrate'] = 'new-hash' |
|
53 | stub_auth_data['_hash_migrate'] = 'new-hash' | |
49 |
plugin = |
|
54 | plugin = TestAuthPlugin('stub_id') | |
50 | with mock.patch.object(plugin, 'auth') as auth_mock: |
|
55 | with mock.patch.object(plugin, 'auth') as auth_mock: | |
51 | auth_mock.return_value = stub_auth_data |
|
56 | auth_mock.return_value = stub_auth_data | |
52 | result = plugin._authenticate(mock.Mock(), 'test', 'password', {}) |
|
57 | result = plugin._authenticate(mock.Mock(), 'test', 'password', {}) | |
@@ -60,7 +65,7 b' def test_authenticate_migrates_to_new_ha' | |||||
60 | new_password = b'new-password' |
|
65 | new_password = b'new-password' | |
61 | new_hash = _RhodeCodeCryptoBCrypt().hash_create(new_password) |
|
66 | new_hash = _RhodeCodeCryptoBCrypt().hash_create(new_password) | |
62 | stub_auth_data['_hash_migrate'] = new_hash |
|
67 | stub_auth_data['_hash_migrate'] = new_hash | |
63 |
plugin = |
|
68 | plugin = TestAuthPlugin('stub_id') | |
64 | with mock.patch.object(plugin, 'auth') as auth_mock: |
|
69 | with mock.patch.object(plugin, 'auth') as auth_mock: | |
65 | auth_mock.return_value = stub_auth_data |
|
70 | auth_mock.return_value = stub_auth_data | |
66 | result = plugin._authenticate( |
|
71 | result = plugin._authenticate( |
General Comments 0
You need to be logged in to leave comments.
Login now