##// END OF EJS Templates
authn: Add an INI option to set an authentication plugin fallback. #3953...
johbo -
r52:a007b8c5 default
parent child Browse files
Show More
@@ -56,7 +56,7 b' def includeme(config):'
56 56 config.set_authentication_policy(authn_policy)
57 57
58 58 # Create authentication plugin registry and add it to the pyramid registry.
59 authn_registry = AuthenticationPluginRegistry()
59 authn_registry = AuthenticationPluginRegistry(config.get_settings())
60 60 config.add_directive('add_authn_plugin', authn_registry.add_authn_plugin)
61 61 config.registry.registerUtility(authn_registry)
62 62
@@ -26,23 +26,16 b' import logging'
26 26 import time
27 27 import traceback
28 28
29 from authomatic import Authomatic
30 from authomatic.adapters import WebObAdapter
31 from authomatic.providers import oauth2, oauth1
32 from pylons import url
33 from pylons.controllers.util import Response
34 from pylons.i18n.translation import _
35 29 from pyramid.threadlocal import get_current_registry
36 30 from sqlalchemy.ext.hybrid import hybrid_property
37 31
38 import rhodecode.lib.helpers as h
39 32 from rhodecode.authentication.interface import IAuthnPluginRegistry
40 33 from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
41 34 from rhodecode.lib import caches
42 35 from rhodecode.lib.auth import PasswordGenerator, _RhodeCodeCryptoBCrypt
43 36 from rhodecode.lib.utils2 import md5_safe, safe_int
44 37 from rhodecode.lib.utils2 import safe_str
45 from rhodecode.model.db import User, ExternalIdentity
38 from rhodecode.model.db import User
46 39 from rhodecode.model.meta import Session
47 40 from rhodecode.model.settings import SettingsModel
48 41 from rhodecode.model.user import UserModel
@@ -518,50 +511,40 b' def authenticate(username, password, env'
518 511 raise ValueError('auth type must be on of http, vcs got "%s" instead'
519 512 % auth_type)
520 513 container_only = environ and not (username and password)
521 auth_plugins = SettingsModel().get_auth_plugins()
522 for plugin_id in auth_plugins:
523 plugin = loadplugin(plugin_id)
524 514
525 if plugin is None:
526 log.warning('Authentication plugin missing: "{}"'.format(
527 plugin_id))
528 continue
529
530 if not plugin.is_active():
531 log.info('Authentication plugin is inactive: "{}"'.format(
532 plugin_id))
533 continue
534
515 authn_registry = get_current_registry().getUtility(IAuthnPluginRegistry)
516 for plugin in authn_registry.get_plugins_for_authentication():
535 517 plugin.set_auth_type(auth_type)
536 518 user = plugin.get_user(username)
537 519 display_user = user.username if user else username
538 520
539 521 if container_only and not plugin.is_container_auth:
540 522 log.debug('Auth type is for container only and plugin `%s` is not '
541 'container plugin, skipping...', plugin_id)
523 'container plugin, skipping...', plugin.get_id())
542 524 continue
543 525
544 526 # load plugin settings from RhodeCode database
545 527 plugin_settings = plugin.get_settings()
546 528 log.debug('Plugin settings:%s', plugin_settings)
547 529
548 log.debug('Trying authentication using ** %s **', plugin_id)
530 log.debug('Trying authentication using ** %s **', plugin.get_id())
549 531 # use plugin's method of user extraction.
550 532 user = plugin.get_user(username, environ=environ,
551 533 settings=plugin_settings)
552 534 display_user = user.username if user else username
553 log.debug('Plugin %s extracted user is `%s`', plugin_id, display_user)
535 log.debug(
536 'Plugin %s extracted user is `%s`', plugin.get_id(), display_user)
554 537
555 538 if not plugin.allows_authentication_from(user):
556 539 log.debug('Plugin %s does not accept user `%s` for authentication',
557 plugin_id, display_user)
540 plugin.get_id(), display_user)
558 541 continue
559 542 else:
560 543 log.debug('Plugin %s accepted user `%s` for authentication',
561 plugin_id, display_user)
544 plugin.get_id(), display_user)
562 545
563 546 log.info('Authenticating user `%s` using %s plugin',
564 display_user, plugin_id)
547 display_user, plugin.get_id())
565 548
566 549 _cache_ttl = 0
567 550
@@ -576,7 +559,7 b' def authenticate(username, password, env'
576 559 # get instance of cache manager configured for a namespace
577 560 cache_manager = get_auth_cache_manager(custom_ttl=_cache_ttl)
578 561
579 log.debug('Cache for plugin `%s` active: %s', plugin_id,
562 log.debug('Cache for plugin `%s` active: %s', plugin.get_id(),
580 563 plugin_cache_active)
581 564
582 565 # for environ based password can be empty, but then the validation is
@@ -591,7 +574,7 b' def authenticate(username, password, env'
591 574 # then auth is correct.
592 575 start = time.time()
593 576 log.debug('Running plugin `%s` _authenticate method',
594 plugin_id)
577 plugin.get_id())
595 578
596 579 def auth_func():
597 580 """
@@ -611,7 +594,7 b' def authenticate(username, password, env'
611 594 auth_time = time.time() - start
612 595 log.debug('Authentication for plugin `%s` completed in %.3fs, '
613 596 'expiration time of fetched cache %.1fs.',
614 plugin_id, auth_time, _cache_ttl)
597 plugin.get_id(), auth_time, _cache_ttl)
615 598
616 599 log.debug('PLUGIN USER DATA: %s', plugin_user)
617 600
@@ -620,5 +603,5 b' def authenticate(username, password, env'
620 603 return plugin_user
621 604 # we failed to Auth because .auth() method didn't return proper user
622 605 log.debug("User `%s` failed to authenticate against %s",
623 display_user, plugin_id)
606 display_user, plugin.get_id())
624 607 return None
@@ -31,8 +31,13 b' log = logging.getLogger(__name__)'
31 31
32 32 @implementer(IAuthnPluginRegistry)
33 33 class AuthenticationPluginRegistry(object):
34 def __init__(self):
34
35 # INI settings key to set a fallback authentication plugin.
36 fallback_plugin_key = 'rhodecode.auth_plugin_fallback'
37
38 def __init__(self, settings):
35 39 self._plugins = {}
40 self._fallback_plugin = settings.get(self.fallback_plugin_key, None)
36 41
37 42 def add_authn_plugin(self, config, plugin):
38 43 plugin_id = plugin.get_id()
@@ -51,3 +56,23 b' class AuthenticationPluginRegistry(objec'
51 56
52 57 def get_plugin(self, plugin_id):
53 58 return self._plugins.get(plugin_id, None)
59
60 def get_plugins_for_authentication(self):
61 """
62 Returns a list of plugins which should be consulted when authenticating
63 a user. It only returns plugins which are enabled and active.
64 Additionally it includes the fallback plugin from the INI file, if
65 `rhodecode.auth_plugin_fallback` is set to a plugin ID.
66 """
67 plugins = []
68 for plugin in self.get_plugins():
69 if (self._fallback_plugin and
70 plugin.get_id() == self._fallback_plugin):
71 log.warn(
72 'Using fallback authentication plugin from INI file: "%s"',
73 plugin.get_id())
74 plugins.append(plugin)
75 elif plugin.is_enabled() and plugin.is_active():
76 plugins.append(plugin)
77
78 return plugins
@@ -151,8 +151,7 b' class AuthSettingsView(object):'
151 151 @HasPermissionAllDecorator('hg.admin')
152 152 def index(self, defaults={}, errors=None, prefix_error=False):
153 153 authn_registry = self.request.registry.getUtility(IAuthnPluginRegistry)
154 default_plugins = ['egg:rhodecode-enterprise-ce#rhodecode']
155 enabled_plugins = SettingsModel().get_auth_plugins() or default_plugins
154 enabled_plugins = SettingsModel().get_auth_plugins()
156 155
157 156 # Create template context and render it.
158 157 template_context = {
General Comments 0
You need to be logged in to leave comments. Login now