# -*- coding: utf-8 -*- # Copyright (C) 2016-2016 RhodeCode GmbH # # 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 . # # 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 token plugin for built in internal auth """ import logging from sqlalchemy.ext.hybrid import hybrid_property from rhodecode.translation import _ from rhodecode.authentication.base import RhodeCodeAuthPluginBase, VCS_TYPE from rhodecode.authentication.routes import AuthnPluginResourceBase from rhodecode.model.db import User, UserApiKeys log = logging.getLogger(__name__) def plugin_factory(plugin_id, *args, **kwds): plugin = RhodeCodeAuthPlugin(plugin_id) return plugin class RhodecodeAuthnResource(AuthnPluginResourceBase): pass class RhodeCodeAuthPlugin(RhodeCodeAuthPluginBase): """ Enables usage of authentication tokens for vcs operations. """ 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', request_method='GET', route_name='auth_home', context=RhodecodeAuthnResource) config.add_view( 'rhodecode.authentication.views.AuthnPluginViewBase', attr='settings_post', request_method='POST', route_name='auth_home', context=RhodecodeAuthnResource) def get_display_name(self): return _('Rhodecode Token Auth') @hybrid_property def name(self): return "authtoken" def user_activation_state(self): def_user_perms = User.get_default_user().AuthUser.permissions['global'] 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 empty users. And also allows rhodecode and authtoken extern_type to auth with this. But only via vcs mode """ # only this and rhodecode plugins can use this type from rhodecode.authentication.plugins import auth_rhodecode allowed_auth_plugins = [ self.name, auth_rhodecode.RhodeCodeAuthPlugin.name] # only for vcs operations allowed_auth_sources = [VCS_TYPE] return super(RhodeCodeAuthPlugin, self).allows_authentication_from( user, allows_non_existing_user=False, allowed_auth_plugins=allowed_auth_plugins, allowed_auth_sources=allowed_auth_sources) def auth(self, userobj, username, password, settings, **kwargs): if not userobj: log.debug('userobj was:%s skipping' % (userobj, )) return None user_attrs = { "username": userobj.username, "firstname": userobj.firstname, "lastname": userobj.lastname, "groups": [], "email": userobj.email, "admin": userobj.admin, "active": userobj.active, "active_from_extern": userobj.active, "extern_name": userobj.user_id, "extern_type": userobj.extern_type, } log.debug('Authenticating user with args %s', user_attrs) if userobj.active: role = UserApiKeys.ROLE_VCS active_tokens = [x.api_key for x in User.extra_valid_auth_tokens(userobj, role=role)] if userobj.username == username and password in active_tokens: log.info( 'user `%s` successfully authenticated via %s', user_attrs['username'], self.name) return user_attrs log.error( 'user `%s` failed to authenticate via %s, reason: bad or ' 'inactive token.', username, self.name) else: log.warning( 'user `%s` failed to authenticate via %s, reason: account not ' 'active.', username, self.name) return None