Changeset - 3b136af34329
[Not reviewed]
default
0 8 0
Marcin Kuzminski - 12 years ago 2013-07-01 16:10:22
marcin@python-works.com
Added pre-create user hook.
It allows to control user creation using rcext hooks.
8 files changed with 137 insertions and 24 deletions:
0 comments (0 inline, 0 general)
rhodecode/config/rcextensions/__init__.py
Show inline comments
 
@@ -50,12 +50,35 @@ def _crrepohook(*args, **kwargs):
 
    """
 
    return 0
 
CREATE_REPO_HOOK = _crrepohook
 

	
 

	
 
#==============================================================================
 
# PRE CREATE USER HOOK
 
#==============================================================================
 
# this function will be executed before each user is created
 
def _pre_cruserhook(*args, **kwargs):
 
    """
 
    Pre create user HOOK, it returns a tuple of bool, reason.
 
    If bool is False the user creation will be stopped and reason
 
    will be displayed to the user.
 
    kwargs available:
 
    :param username:
 
    :param password:
 
    :param email:
 
    :param firstname:
 
    :param lastname:
 
    :param active:
 
    :param admin:
 
    :param created_by:
 
    """
 
    reason = 'allowed'
 
    return True, reason
 
PRE_CREATE_USER_HOOK = _pre_cruserhook
 

	
 
#==============================================================================
 
# POST CREATE USER HOOK
 
#==============================================================================
 
# this function will be executed after each user is created
 
def _cruserhook(*args, **kwargs):
 
    """
 
    Post create user HOOK
rhodecode/controllers/admin/users.py
Show inline comments
 
@@ -32,13 +32,13 @@ from formencode import htmlfill
 
from pylons import request, session, tmpl_context as c, url, config
 
from pylons.controllers.util import redirect
 
from pylons.i18n.translation import _
 

	
 
import rhodecode
 
from rhodecode.lib.exceptions import DefaultUserException, \
 
    UserOwnsReposException
 
    UserOwnsReposException, UserCreationError
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    AuthUser
 
from rhodecode.lib.base import BaseController, render
 

	
 
from rhodecode.model.db import User, UserEmailMap, UserIpMap, UserToPerm
 
@@ -134,12 +134,14 @@ class UsersController(BaseController):
 
            return htmlfill.render(
 
                render('admin/users/user_add.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 
        except UserCreationError, e:
 
            h.flash(e, 'error')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('Error occurred during creation of user %s') \
 
                    % request.POST.get('username'), category='error')
 
        return redirect(url('users'))
 

	
rhodecode/controllers/login.py
Show inline comments
 
@@ -34,12 +34,13 @@ from pylons.i18n.translation import _
 
from pylons.controllers.util import abort, redirect
 
from pylons import request, response, session, tmpl_context as c, url
 

	
 
import rhodecode.lib.helpers as h
 
from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.exceptions import UserCreationError
 
from rhodecode.model.db import User
 
from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.meta import Session
 

	
 

	
 
@@ -117,12 +118,18 @@ class LoginController(BaseController):
 
                return htmlfill.render(
 
                    render('/login.html'),
 
                    defaults=errors.value,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8")
 
            except UserCreationError, e:
 
                # container auth or other auth functions that create users on
 
                # the fly can throw this exception signaling that there's issue
 
                # with user creation, explanation should be provided in
 
                # Exception itself
 
                h.flash(e, 'error')
 

	
 
        return render('/login.html')
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
 
                               'hg.register.manual_activate')
 
    def register(self):
 
@@ -144,12 +151,18 @@ class LoginController(BaseController):
 
                return htmlfill.render(
 
                    render('/register.html'),
 
                    defaults=errors.value,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8")
 
            except UserCreationError, e:
 
                # container auth or other auth functions that create users on
 
                # the fly can throw this exception signaling that there's issue
 
                # with user creation, explanation should be provided in
 
                # Exception itself
 
                h.flash(e, 'error')
 

	
 
        return render('/register.html')
 

	
 
    def password_reset(self):
 
        if request.POST:
 
            password_reset_form = PasswordResetForm()()
rhodecode/lib/base.py
Show inline comments
 
@@ -19,12 +19,13 @@ from rhodecode import __version__, BACKE
 

	
 
from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict,\
 
    safe_str, safe_int
 
from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\
 
    HasPermissionAnyMiddleware, CookieStoreWrapper
 
from rhodecode.lib.utils import get_repo_slug
 
from rhodecode.lib.exceptions import UserCreationError
 
from rhodecode.model import meta
 

	
 
from rhodecode.model.db import Repository, RhodeCodeUi, User, RhodeCodeSetting
 
from rhodecode.model.notification import NotificationModel
 
from rhodecode.model.scm import ScmModel
 
from rhodecode.model.meta import Session
 
@@ -297,13 +298,23 @@ class BaseController(WSGIController):
 
            self.ip_addr = _get_ip_addr(environ)
 
            # make sure that we update permissions each time we call controller
 
            api_key = request.GET.get('api_key')
 
            cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
 
            user_id = cookie_store.get('user_id', None)
 
            username = get_container_username(environ, config)
 
            auth_user = AuthUser(user_id, api_key, username, self.ip_addr)
 
            try:
 
                auth_user = AuthUser(user_id, api_key, username, self.ip_addr)
 
            except UserCreationError, e:
 
                from rhodecode.lib import helpers as h
 
                h.flash(e, 'error')
 
                # container auth or other auth functions that create users on
 
                # the fly can throw this exception signaling that there's issue
 
                # with user creation, explanation should be provided in
 
                # Exception itself
 
                auth_user = AuthUser(ip_addr=self.ip_addr)
 

	
 
            request.user = auth_user
 
            self.rhodecode_user = c.rhodecode_user = auth_user
 
            if not self.rhodecode_user.is_authenticated and \
 
                       self.rhodecode_user.user_id is not None:
 
                self.rhodecode_user.set_authenticated(
 
                    cookie_store.get('is_authenticated')
rhodecode/lib/exceptions.py
Show inline comments
 
@@ -87,6 +87,14 @@ class HTTPLockedRC(HTTPClientError):
 
                                         'user `%s`' % (reponame, username))
 
        super(HTTPLockedRC, self).__init__(*args, **kwargs)
 

	
 

	
 
class IMCCommitError(Exception):
 
    pass
 

	
 

	
 
class UserCreationError(Exception):
 
    pass
 

	
 

	
 
class RepositoryCreationError(Exception):
 
    pass
rhodecode/lib/hooks.py
Show inline comments
 
@@ -31,13 +31,13 @@ from inspect import isfunction
 

	
 
from rhodecode.lib.vcs.utils.hgcompat import nullrev, revrange
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.utils import action_logger
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.exceptions import HTTPLockedRC
 
from rhodecode.lib.exceptions import HTTPLockedRC, UserCreationError
 
from rhodecode.lib.utils2 import safe_str, _extract_extras
 
from rhodecode.model.db import Repository, User
 

	
 

	
 
def _get_scm_size(alias, root_path):
 

	
 
@@ -249,12 +249,21 @@ def log_create_repository(repository_dic
 
        kw.update(kwargs)
 
        return callback(**kw)
 

	
 
    return 0
 

	
 

	
 
def check_allowed_create_user(user_dict, created_by, **kwargs):
 
    from rhodecode import EXTENSIONS
 
    callback = getattr(EXTENSIONS, 'PRE_CREATE_USER_HOOK', None)
 
    if isfunction(callback):
 
        allowed, reason = callback(created_by=created_by, **user_dict)
 
        if not allowed:
 
            raise UserCreationError(reason)
 

	
 

	
 
def log_create_user(user_dict, created_by, **kwargs):
 
    """
 
    Post create user Hook. This is a dummy function for admins to re-use
 
    if needed. It's taken from rhodecode-extensions module and executed
 
    if present
 

	
rhodecode/model/user.py
Show inline comments
 
@@ -33,15 +33,15 @@ from pylons.i18n.translation import _
 
from sqlalchemy.exc import DatabaseError
 
from sqlalchemy.orm import joinedload
 

	
 
from rhodecode.lib.utils2 import safe_unicode, generate_api_key, get_current_rhodecode_user
 
from rhodecode.lib.caching_query import FromCache
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
 
from rhodecode.model.db import User, Repository, Permission, \
 
    UserToPerm, UserGroupRepoToPerm, UserGroupToPerm, UserGroupMember, \
 
    Notification, RepoGroup, UserRepoGroupToPerm, UserGroupRepoGroupToPerm, \
 
    Notification, RepoGroup, UserGroupRepoGroupToPerm, \
 
    UserEmailMap, UserIpMap, UserGroupUserGroupToPerm, UserGroup
 
from rhodecode.lib.exceptions import DefaultUserException, \
 
    UserOwnsReposException
 
from rhodecode.model.meta import Session
 

	
 

	
 
@@ -80,12 +80,23 @@ class UserModel(BaseModel):
 
    def get_by_api_key(self, api_key, cache=False):
 
        return User.get_by_api_key(api_key, cache)
 

	
 
    def create(self, form_data, cur_user=None):
 
        if not cur_user:
 
            cur_user = getattr(get_current_rhodecode_user(), 'username', None)
 

	
 
        from rhodecode.lib.hooks import log_create_user, check_allowed_create_user
 
        _fd = form_data
 
        form_data = {
 
            'username': _fd['username'], 'password': _fd['password'],
 
            'email': _fd['email'], 'firstname': _fd['firstname'], 'lastname': _fd['lastname'],
 
            'active': _fd['active'], 'admin': False
 
        }
 
        # raises UserCreationError if it's not allowed
 
        check_allowed_create_user(form_data, cur_user)
 

	
 
        from rhodecode.lib.auth import get_crypt_password
 
        try:
 
            new_user = User()
 
            for k, v in form_data.items():
 
                if k == 'password':
 
                    v = get_crypt_password(v)
 
@@ -93,13 +104,12 @@ class UserModel(BaseModel):
 
                    k = 'name'
 
                setattr(new_user, k, v)
 

	
 
            new_user.api_key = generate_api_key(form_data['username'])
 
            self.sa.add(new_user)
 

	
 
            from rhodecode.lib.hooks import log_create_user
 
            log_create_user(new_user.get_dict(), cur_user)
 
            return new_user
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
@@ -121,12 +131,20 @@ class UserModel(BaseModel):
 
        :param cur_user:
 
        """
 
        if not cur_user:
 
            cur_user = getattr(get_current_rhodecode_user(), 'username', None)
 

	
 
        from rhodecode.lib.auth import get_crypt_password
 
        from rhodecode.lib.hooks import log_create_user, check_allowed_create_user
 
        form_data = {
 
            'username': username, 'password': password,
 
            'email': email, 'firstname': firstname, 'lastname': lastname,
 
            'active': active, 'admin': admin
 
        }
 
        # raises UserCreationError if it's not allowed
 
        check_allowed_create_user(form_data, cur_user)
 

	
 
        log.debug('Checking for %s account in RhodeCode database' % username)
 
        user = User.get_by_username(username, case_insensitive=True)
 
        if user is None:
 
            log.debug('creating new user %s' % username)
 
            new_user = User()
 
@@ -148,13 +166,12 @@ class UserModel(BaseModel):
 
            new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
 
            new_user.name = firstname
 
            new_user.lastname = lastname
 
            self.sa.add(new_user)
 

	
 
            if not edit:
 
                from rhodecode.lib.hooks import log_create_user
 
                log_create_user(new_user.get_dict(), cur_user)
 
            return new_user
 
        except (DatabaseError,):
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
@@ -166,29 +183,39 @@ class UserModel(BaseModel):
 
        :param attrs:
 
        :param cur_user:
 
        """
 
        if not cur_user:
 
            cur_user = getattr(get_current_rhodecode_user(), 'username', None)
 
        if self.get_by_username(username, case_insensitive=True) is None:
 

	
 
            # autogenerate email for container account without one
 
            generate_email = lambda usr: '%s@container_auth.account' % usr
 
            firstname = attrs['name']
 
            lastname = attrs['lastname']
 
            active = attrs.get('active', True)
 
            email = attrs['email'] or generate_email(username)
 

	
 
            from rhodecode.lib.hooks import log_create_user, check_allowed_create_user
 
            form_data = {
 
                'username': username, 'password': None,
 
                'email': email, 'firstname': firstname, 'lastname': lastname,
 
                'active': attrs.get('active', True), 'admin': False
 
            }
 
            # raises UserCreationError if it's not allowed
 
            check_allowed_create_user(form_data, cur_user)
 

	
 
            try:
 
                new_user = User()
 
                new_user.username = username
 
                new_user.password = None
 
                new_user.api_key = generate_api_key(username)
 
                new_user.email = attrs['email']
 
                new_user.active = attrs.get('active', True)
 
                new_user.name = attrs['name'] or generate_email(username)
 
                new_user.lastname = attrs['lastname']
 
                new_user.email = email
 
                new_user.active = active
 
                new_user.name = firstname
 
                new_user.lastname = lastname
 

	
 
                self.sa.add(new_user)
 

	
 
                from rhodecode.lib.hooks import log_create_user
 
                log_create_user(new_user.get_dict(), cur_user)
 
                return new_user
 
            except (DatabaseError,):
 
                log.error(traceback.format_exc())
 
                self.sa.rollback()
 
                raise
 
@@ -209,32 +236,43 @@ class UserModel(BaseModel):
 
        """
 
        if not cur_user:
 
            cur_user = getattr(get_current_rhodecode_user(), 'username', None)
 
        from rhodecode.lib.auth import get_crypt_password
 
        log.debug('Checking for such ldap account in RhodeCode database')
 
        if self.get_by_username(username, case_insensitive=True) is None:
 
            # autogenerate email for container account without one
 
            generate_email = lambda usr: '%s@ldap.account' % usr
 
            password = get_crypt_password(password)
 
            firstname = attrs['name']
 
            lastname = attrs['lastname']
 
            active = attrs.get('active', True)
 
            email = attrs['email'] or generate_email(username)
 

	
 
            # autogenerate email for ldap account without one
 
            generate_email = lambda usr: '%s@ldap.account' % usr
 
            from rhodecode.lib.hooks import log_create_user, check_allowed_create_user
 
            form_data = {
 
                'username': username, 'password': password,
 
                'email': email, 'firstname': firstname, 'lastname': lastname,
 
                'active': attrs.get('active', True), 'admin': False
 
            }
 
            # raises UserCreationError if it's not allowed
 
            check_allowed_create_user(form_data, cur_user)
 

	
 
            try:
 
                new_user = User()
 
                username = username.lower()
 
                # add ldap account always lowercase
 
                new_user.username = username
 
                new_user.password = get_crypt_password(password)
 
                new_user.password = password
 
                new_user.api_key = generate_api_key(username)
 
                new_user.email = attrs['email'] or generate_email(username)
 
                new_user.active = attrs.get('active', True)
 
                new_user.email = email
 
                new_user.active = active
 
                new_user.ldap_dn = safe_unicode(user_dn)
 
                new_user.name = attrs['name']
 
                new_user.lastname = attrs['lastname']
 

	
 
                new_user.name = firstname
 
                new_user.lastname = lastname
 
                self.sa.add(new_user)
 

	
 
                from rhodecode.lib.hooks import log_create_user
 
                log_create_user(new_user.get_dict(), cur_user)
 
                return new_user
 
            except (DatabaseError,):
 
                log.error(traceback.format_exc())
 
                self.sa.rollback()
 
                raise
rhodecode/templates/register.html
Show inline comments
 
@@ -3,13 +3,22 @@
 

	
 
<%def name="title()">
 
    ${_('Sign Up')} &middot; ${c.rhodecode_name}
 
</%def>
 

	
 
<div id="register">
 

	
 
<div class="flash_msg">
 
    <% messages = h.flash.pop_messages() %>
 
    % if messages:
 
    <ul id="flash-messages">
 
        % for message in messages:
 
        <li class="${message.category}_msg">${message}</li>
 
        % endfor
 
    </ul>
 
    % endif
 
</div>
 
    <div class="title top-left-rounded-corner top-right-rounded-corner">
 
        <h5>${_('Sign Up to')} ${c.rhodecode_name}</h5>
 
    </div>
 
    <div class="inner">
 
        ${h.form(url('register'))}
 
        <div class="form">
0 comments (0 inline, 0 general)