##// END OF EJS Templates
authentication: fixed for python3 migrations
super-admin -
r5057:c3d4b375 default
parent child Browse files
Show More
@@ -21,7 +21,7 b''
21 21 import logging
22 22 import importlib
23 23
24 from pyramid.authentication import SessionAuthenticationPolicy
24 from pyramid.authentication import SessionAuthenticationHelper
25 25
26 26 from rhodecode.authentication.registry import AuthenticationPluginRegistry
27 27 from rhodecode.authentication.routes import root_factory
@@ -70,9 +70,7 b' def discover_legacy_plugins(config, pref'
70 70
71 71 def includeme(config):
72 72
73 # Set authentication policy.
74 authn_policy = SessionAuthenticationPolicy()
75 config.set_authentication_policy(authn_policy)
73 config.set_security_policy(SessionAuthenticationHelper())
76 74
77 75 # Create authentication plugin registry and add it to the pyramid registry.
78 76 authn_registry = AuthenticationPluginRegistry(config.get_settings())
@@ -32,11 +32,13 b' import functools'
32 32
33 33 from pyramid.threadlocal import get_current_registry
34 34
35 from rhodecode.authentication import AuthenticationPluginRegistry
35 36 from rhodecode.authentication.interface import IAuthnPluginRegistry
36 37 from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
37 38 from rhodecode.lib import rc_cache
38 39 from rhodecode.lib.statsd_client import StatsdClient
39 40 from rhodecode.lib.auth import PasswordGenerator, _RhodeCodeCryptoBCrypt
41 from rhodecode.lib.str_utils import safe_bytes
40 42 from rhodecode.lib.utils2 import safe_int, safe_str
41 43 from rhodecode.lib.exceptions import (LdapConnectionError, LdapUsernameError, LdapPasswordError)
42 44 from rhodecode.model.db import User
@@ -377,12 +379,13 b' class RhodeCodeAuthPluginBase(object):'
377 379 def get_user(self, username=None, **kwargs):
378 380 """
379 381 Helper method for user fetching in plugins, by default it's using
380 simple fetch by username, but this method can be custimized in plugins
382 simple fetch by username, but this method can be customized in plugins
381 383 eg. headers auth plugin to fetch user by environ params
382 384
383 385 :param username: username if given to fetch from database
384 386 :param kwargs: extra arguments needed for user fetching.
385 387 """
388
386 389 user = None
387 390 log.debug(
388 391 'Trying to fetch user `%s` from RhodeCode database', username)
@@ -437,6 +440,7 b' class RhodeCodeAuthPluginBase(object):'
437 440 # check if hash should be migrated ?
438 441 new_hash = auth.get('_hash_migrate')
439 442 if new_hash:
443 # new_hash is a newly encrypted destination hash
440 444 self._migrate_hash_to_bcrypt(username, passwd, new_hash)
441 445 if 'user_group_sync' not in auth:
442 446 auth['user_group_sync'] = False
@@ -446,9 +450,9 b' class RhodeCodeAuthPluginBase(object):'
446 450 def _migrate_hash_to_bcrypt(self, username, password, new_hash):
447 451 new_hash_cypher = _RhodeCodeCryptoBCrypt()
448 452 # extra checks, so make sure new hash is correct.
449 password_encoded = safe_str(password)
450 if new_hash and new_hash_cypher.hash_check(
451 password_encoded, new_hash):
453 password_as_bytes = safe_bytes(password)
454
455 if new_hash and new_hash_cypher.hash_check(password_as_bytes, new_hash):
452 456 cur_user = User.get_by_username(username)
453 457 cur_user.password = new_hash
454 458 Session().add(cur_user)
@@ -671,7 +675,7 b' def loadplugin(plugin_id):'
671 675 return plugin
672 676
673 677
674 def get_authn_registry(registry=None):
678 def get_authn_registry(registry=None) -> AuthenticationPluginRegistry:
675 679 registry = registry or get_current_registry()
676 680 authn_registry = registry.queryUtility(IAuthnPluginRegistry)
677 681 return authn_registry
@@ -688,18 +692,23 b' def authenticate(username, password, env'
688 692 :param environ: environ headers passed for headers auth
689 693 :param auth_type: type of authentication, either `HTTP_TYPE` or `VCS_TYPE`
690 694 :param skip_missing: ignores plugins that are in db but not in environment
695 :param registry: pyramid registry
696 :param acl_repo_name: name of repo for ACL checks
691 697 :returns: None if auth failed, plugin_user dict if auth is correct
692 698 """
693 699 if not auth_type or auth_type not in [HTTP_TYPE, VCS_TYPE]:
694 raise ValueError('auth type must be on of http, vcs got "%s" instead'
695 % auth_type)
696 headers_only = environ and not (username and password)
700 raise ValueError(f'auth type must be on of http, vcs got "{auth_type}" instead')
701
702 auth_credentials = (username and password)
703 headers_only = environ and not auth_credentials
697 704
698 705 authn_registry = get_authn_registry(registry)
699 706
700 707 plugins_to_check = authn_registry.get_plugins_for_authentication()
708 log.debug('authentication: headers=%s, username_and_passwd=%s', headers_only, bool(auth_credentials))
701 709 log.debug('Starting ordered authentication chain using %s plugins',
702 710 [x.name for x in plugins_to_check])
711
703 712 for plugin in plugins_to_check:
704 713 plugin.set_auth_type(auth_type)
705 714 plugin.set_calling_scope_repo(acl_repo_name)
@@ -26,7 +26,9 b' RhodeCode authentication plugin for Atla'
26 26 import colander
27 27 import base64
28 28 import logging
29 import urllib.request, urllib.error, urllib.parse
29 import urllib.request
30 import urllib.error
31 import urllib.parse
30 32
31 33 from rhodecode.translation import _
32 34 from rhodecode.authentication.base import (
@@ -27,7 +27,8 b' from rhodecode.authentication.base impor'
27 27 from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
28 28 from rhodecode.authentication.routes import AuthnPluginResourceBase
29 29 from rhodecode.lib.colander_utils import strip_whitespace
30 from rhodecode.lib.utils2 import str2bool, safe_unicode
30 from rhodecode.lib.str_utils import safe_str
31 from rhodecode.lib.utils2 import str2bool
31 32 from rhodecode.model.db import User
32 33
33 34
@@ -149,7 +150,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
149 150 def get_user(self, username=None, **kwargs):
150 151 """
151 152 Helper method for user fetching in plugins, by default it's using
152 simple fetch by username, but this method can be custimized in plugins
153 simple fetch by username, but this method can be customized in plugins
153 154 eg. headers auth plugin to fetch user by environ params
154 155 :param username: username if given to fetch
155 156 :param kwargs: extra arguments needed for user fetching.
@@ -162,7 +163,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
162 163
163 164 def auth(self, userobj, username, password, settings, **kwargs):
164 165 """
165 Get's the headers_auth username (or email). It tries to get username
166 Gets the headers_auth username (or email). It tries to get username
166 167 from REMOTE_USER if this plugin is enabled, if that fails
167 168 it tries to get username from HTTP_X_FORWARDED_USER if fallback header
168 169 is set. clean_username extracts the username from this data if it's
@@ -210,8 +211,8 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
210 211
211 212 user_attrs = {
212 213 'username': username,
213 'firstname': safe_unicode(firstname or username),
214 'lastname': safe_unicode(lastname or ''),
214 'firstname': safe_str(firstname or username),
215 'lastname': safe_str(lastname or ''),
215 216 'groups': [],
216 217 'user_group_sync': False,
217 218 'email': email or '',
@@ -27,8 +27,10 b' http://www.jasig.org/cas'
27 27 import colander
28 28 import logging
29 29 import rhodecode
30 import urllib.request, urllib.parse, urllib.error
31 import urllib.request, urllib.error, urllib.parse
30 import urllib.request
31 import urllib.parse
32 import urllib.error
33
32 34
33 35 from rhodecode.translation import _
34 36 from rhodecode.authentication.base import (
@@ -36,8 +38,8 b' from rhodecode.authentication.base impor'
36 38 from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
37 39 from rhodecode.authentication.routes import AuthnPluginResourceBase
38 40 from rhodecode.lib.colander_utils import strip_whitespace
39 from rhodecode.lib.utils2 import safe_unicode
40 41 from rhodecode.model.db import User
42 from rhodecode.lib.str_utils import safe_str
41 43
42 44 log = logging.getLogger(__name__)
43 45
@@ -133,12 +135,12 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
133 135 {"url": url, "body": params, "headers": headers})
134 136 request = urllib.request.Request(url, params, headers)
135 137 try:
136 response = urllib.request.urlopen(request)
138 urllib.request.urlopen(request)
137 139 except urllib.error.HTTPError as e:
138 140 log.debug("HTTPError when requesting Jasig CAS (status code: %d)", e.code)
139 141 return None
140 142 except urllib.error.URLError as e:
141 log.debug("URLError when requesting Jasig CAS url: %s ", url)
143 log.debug("URLError when requesting Jasig CAS url: %s %s", url, e)
142 144 return None
143 145
144 146 # old attrs fetched from RhodeCode database
@@ -152,8 +154,8 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
152 154
153 155 user_attrs = {
154 156 'username': username,
155 'firstname': safe_unicode(firstname or username),
156 'lastname': safe_unicode(lastname or ''),
157 'firstname': safe_str(firstname or username),
158 'lastname': safe_str(lastname or ''),
157 159 'groups': [],
158 160 'user_group_sync': False,
159 161 'email': email or '',
@@ -34,7 +34,7 b' from rhodecode.lib.colander_utils import'
34 34 from rhodecode.lib.exceptions import (
35 35 LdapConnectionError, LdapUsernameError, LdapPasswordError, LdapImportError
36 36 )
37 from rhodecode.lib.utils2 import safe_unicode, safe_str
37 from rhodecode.lib.str_utils import safe_str
38 38 from rhodecode.model.db import User
39 39 from rhodecode.model.validators import Missing
40 40
@@ -520,8 +520,8 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
520 520
521 521 user_attrs = {
522 522 'username': username,
523 'firstname': safe_unicode(get_ldap_attr('attr_firstname') or firstname),
524 'lastname': safe_unicode(get_ldap_attr('attr_lastname') or lastname),
523 'firstname': safe_str(get_ldap_attr('attr_firstname') or firstname),
524 'lastname': safe_str(get_ldap_attr('attr_lastname') or lastname),
525 525 'groups': groups,
526 526 'user_group_sync': False,
527 527 'email': get_ldap_attr('attr_email') or email,
@@ -27,7 +27,7 b' import logging'
27 27 import colander
28 28
29 29 from rhodecode.translation import _
30 from rhodecode.lib.utils2 import safe_str
30 from rhodecode.lib.utils2 import safe_bytes
31 31 from rhodecode.model.db import User
32 32 from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
33 33 from rhodecode.authentication.base import (
@@ -153,7 +153,7 b' class RhodeCodeAuthPlugin(RhodeCodeAuthP'
153 153 if userobj.active:
154 154 from rhodecode.lib import auth
155 155 crypto_backend = auth.crypto_backend()
156 password_encoded = safe_str(password)
156 password_encoded = safe_bytes(password)
157 157 password_match, new_hash = crypto_backend.hash_check_with_upgrade(
158 158 password_encoded, userobj.password or '')
159 159
@@ -66,25 +66,19 b' class AuthenticationPluginRegistry(objec'
66 66 if plugin.uid == plugin_uid:
67 67 return plugin
68 68
69 def get_plugins_for_authentication(self, cache=True):
70 """
71 Returns a list of plugins which should be consulted when authenticating
72 a user. It only returns plugins which are enabled and active.
73 Additionally it includes the fallback plugin from the INI file, if
74 `rhodecode.auth_plugin_fallback` is set to a plugin ID.
75 """
76
77 cache_namespace_uid = 'cache_auth_plugins'
78 region = rc_cache.get_or_create_region('cache_general', cache_namespace_uid)
69 def get_cache_call_method(self, cache=True):
70 region, _ns = self.get_cache_region()
79 71
80 72 @region.conditional_cache_on_arguments(condition=cache)
81 def _get_auth_plugins(name, key, fallback_plugin):
82 plugins = []
73 def _get_auth_plugins(name: str, key: str, fallback_plugin):
74 log.debug('auth-plugins: calculating plugins available for authentication')
83 75
76 _plugins = []
84 77 # Add all enabled and active plugins to the list. We iterate over the
85 78 # auth_plugins setting from DB because it also represents the ordering.
86 79 enabled_plugins = SettingsModel().get_auth_plugins()
87 80 raw_settings = SettingsModel().get_all_settings(cache=False)
81
88 82 for plugin_id in enabled_plugins:
89 83 plugin = self.get_plugin(plugin_id)
90 84 if plugin is not None and plugin.is_active(
@@ -92,7 +86,7 b' class AuthenticationPluginRegistry(objec'
92 86
93 87 # inject settings into plugin, we can re-use the DB fetched settings here
94 88 plugin._settings = plugin._propagate_settings(raw_settings)
95 plugins.append(plugin)
89 _plugins.append(plugin)
96 90
97 91 # Add the fallback plugin from ini file.
98 92 if fallback_plugin:
@@ -100,10 +94,22 b' class AuthenticationPluginRegistry(objec'
100 94 'Using fallback authentication plugin from INI file: "%s"',
101 95 fallback_plugin)
102 96 plugin = self.get_plugin(fallback_plugin)
103 if plugin is not None and plugin not in plugins:
97 if plugin is not None and plugin not in _plugins:
104 98 plugin._settings = plugin._propagate_settings(raw_settings)
105 plugins.append(plugin)
106 return plugins
99 _plugins.append(plugin)
100 return _plugins
101
102 return _get_auth_plugins
103
104 def get_plugins_for_authentication(self, cache=True):
105 """
106 Returns a list of plugins which should be consulted when authenticating
107 a user. It only returns plugins which are enabled and active.
108 Additionally, it includes the fallback plugin from the INI file, if
109 `rhodecode.auth_plugin_fallback` is set to a plugin ID.
110 """
111
112 _get_auth_plugins = self.get_cache_call_method(cache=cache)
107 113
108 114 start = time.time()
109 115 plugins = _get_auth_plugins('rhodecode_auth_plugins', 'v1', self._fallback_plugin)
@@ -119,3 +125,17 b' class AuthenticationPluginRegistry(objec'
119 125
120 126 return plugins
121 127
128 @classmethod
129 def get_cache_region(cls):
130 cache_namespace_uid = 'auth_plugins'
131 region = rc_cache.get_or_create_region('cache_general', cache_namespace_uid)
132 return region, cache_namespace_uid
133
134 @classmethod
135 def invalidate_auth_plugins_cache(cls, hard=True):
136 region, namespace_key = cls.get_cache_region()
137 log.debug('Invalidation cache [%s] region %s for cache_key: %s',
138 'invalidate_auth_plugins_cache', region, namespace_key)
139
140 # we use hard cleanup if invalidation is sent
141 rc_cache.clear_cache_namespace(region, namespace_key, method=rc_cache.CLEAR_DELETE)
General Comments 0
You need to be logged in to leave comments. Login now