auth_rhodecode.py
153 lines
| 5.7 KiB
| text/x-python
|
PythonLexer
r1 | # -*- coding: utf-8 -*- | |||
r3363 | # Copyright (C) 2012-2019 RhodeCode GmbH | |||
r1 | # | |||
# This program is free software: you can redistribute it and/or modify | ||||
# it under the terms of the GNU Affero General Public License, version 3 | ||||
# (only), as published by the Free Software Foundation. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU Affero General Public License | ||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
# | ||||
# This program is dual-licensed. If you wish to learn more about the | ||||
# RhodeCode Enterprise Edition, including its added features, Support services, | ||||
# and proprietary license terms, please see https://rhodecode.com/licenses/ | ||||
""" | ||||
RhodeCode authentication plugin for built in internal auth | ||||
""" | ||||
import logging | ||||
r2098 | from rhodecode.translation import _ | |||
r1 | ||||
r1454 | from rhodecode.authentication.base import RhodeCodeAuthPluginBase, hybrid_property | |||
r1 | from rhodecode.authentication.routes import AuthnPluginResourceBase | |||
from rhodecode.lib.utils2 import safe_str | ||||
from rhodecode.model.db import User | ||||
log = logging.getLogger(__name__) | ||||
r3253 | def plugin_factory(plugin_id, *args, **kwargs): | |||
r1 | plugin = RhodeCodeAuthPlugin(plugin_id) | |||
return plugin | ||||
class RhodecodeAuthnResource(AuthnPluginResourceBase): | ||||
pass | ||||
class RhodeCodeAuthPlugin(RhodeCodeAuthPluginBase): | ||||
r3246 | uid = 'rhodecode' | |||
r1 | ||||
def includeme(self, config): | ||||
config.add_authn_plugin(self) | ||||
config.add_authn_resource(self.get_id(), RhodecodeAuthnResource(self)) | ||||
config.add_view( | ||||
'rhodecode.authentication.views.AuthnPluginViewBase', | ||||
attr='settings_get', | ||||
r1282 | renderer='rhodecode:templates/admin/auth/plugin_settings.mako', | |||
r1 | request_method='GET', | |||
route_name='auth_home', | ||||
context=RhodecodeAuthnResource) | ||||
config.add_view( | ||||
'rhodecode.authentication.views.AuthnPluginViewBase', | ||||
attr='settings_post', | ||||
r1282 | renderer='rhodecode:templates/admin/auth/plugin_settings.mako', | |||
r1 | request_method='POST', | |||
route_name='auth_home', | ||||
context=RhodecodeAuthnResource) | ||||
def get_display_name(self): | ||||
r3234 | return _('RhodeCode Internal') | |||
r1 | ||||
r3253 | @classmethod | |||
def docs(cls): | ||||
return "https://docs.rhodecode.com/RhodeCode-Enterprise/auth/auth.html" | ||||
r1 | @hybrid_property | |||
def name(self): | ||||
r3256 | return u"rhodecode" | |||
r1 | ||||
def user_activation_state(self): | ||||
r1997 | def_user_perms = User.get_default_user().AuthUser().permissions['global'] | |||
r1 | return 'hg.register.auto_activate' in def_user_perms | |||
def allows_authentication_from( | ||||
self, user, allows_non_existing_user=True, | ||||
allowed_auth_plugins=None, allowed_auth_sources=None): | ||||
""" | ||||
Custom method for this auth that doesn't accept non existing users. | ||||
We know that user exists in our database. | ||||
""" | ||||
allows_non_existing_user = False | ||||
return super(RhodeCodeAuthPlugin, self).allows_authentication_from( | ||||
user, allows_non_existing_user=allows_non_existing_user) | ||||
def auth(self, userobj, username, password, settings, **kwargs): | ||||
if not userobj: | ||||
r3061 | log.debug('userobj was:%s skipping', userobj) | |||
r1 | return None | |||
if userobj.extern_type != self.name: | ||||
log.warning( | ||||
r3061 | "userobj:%s extern_type mismatch got:`%s` expected:`%s`", | |||
userobj, userobj.extern_type, self.name) | ||||
r1 | return None | |||
user_attrs = { | ||||
"username": userobj.username, | ||||
"firstname": userobj.firstname, | ||||
"lastname": userobj.lastname, | ||||
"groups": [], | ||||
r2495 | 'user_group_sync': False, | |||
r1 | "email": userobj.email, | |||
"admin": userobj.admin, | ||||
"active": userobj.active, | ||||
"active_from_extern": userobj.active, | ||||
"extern_name": userobj.user_id, | ||||
"extern_type": userobj.extern_type, | ||||
} | ||||
r3061 | log.debug("User attributes:%s", user_attrs) | |||
r1 | if userobj.active: | |||
from rhodecode.lib import auth | ||||
crypto_backend = auth.crypto_backend() | ||||
password_encoded = safe_str(password) | ||||
password_match, new_hash = crypto_backend.hash_check_with_upgrade( | ||||
r2153 | password_encoded, userobj.password or '') | |||
r1 | ||||
if password_match and new_hash: | ||||
log.debug('user %s properly authenticated, but ' | ||||
'requires hash change to bcrypt', userobj) | ||||
# if password match, and we use OLD deprecated hash, | ||||
# we should migrate this user hash password to the new hash | ||||
# we store the new returned by hash_check_with_upgrade function | ||||
user_attrs['_hash_migrate'] = new_hash | ||||
if userobj.username == User.DEFAULT_USER and userobj.active: | ||||
log.info( | ||||
r2679 | 'user `%s` authenticated correctly as anonymous user', userobj.username) | |||
r1 | return user_attrs | |||
elif userobj.username == username and password_match: | ||||
r2679 | log.info('user `%s` authenticated correctly', userobj.username) | |||
r1 | return user_attrs | |||
r2679 | log.warn("user `%s` used a wrong password when " | |||
"authenticating on this plugin", userobj.username) | ||||
r1 | return None | |||
else: | ||||
r441 | log.warning( | |||
'user `%s` failed to authenticate via %s, reason: account not ' | ||||
'active.', username, self.name) | ||||
r1 | return None | |||
r3240 | ||||
def includeme(config): | ||||
r3246 | plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid) | |||
r3240 | plugin_factory(plugin_id).includeme(config) | |||