Changeset - 1bb0fcdec895
[Not reviewed]
beta
0 6 0
Marcin Kuzminski - 15 years ago 2010-11-18 03:29:23
marcin@python-works.com
fixed #72 show warning on removal when user still is owner of existing repositories
cleaned up exceptions
6 files changed with 52 insertions and 25 deletions:
0 comments (0 inline, 0 general)
rhodecode/controllers/admin/users.py
Show inline comments
 
@@ -18,30 +18,31 @@
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on April 4, 2010
 
users controller for pylons
 
@author: marcink
 
"""
 

	
 
from formencode import htmlfill
 
from pylons import request, session, tmpl_context as c, url
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 
from rhodecode.lib.exceptions import *
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.model.db import User, UserLog
 
from rhodecode.model.db import User
 
from rhodecode.model.forms import UserForm
 
from rhodecode.model.user import UserModel, DefaultUserException
 
from rhodecode.model.user import UserModel
 
import formencode
 
import logging
 
import traceback
 

	
 
log = logging.getLogger(__name__)
 

	
 
class UsersController(BaseController):
 
    """REST Controller styled on the Atom Publishing Protocol"""
 
    # To properly map this controller, ensure your config/routing.py
 
    # file has a resource setup:
 
    #     map.resource('user', 'users')
 

	
 
@@ -126,25 +127,25 @@ class UsersController(BaseController):
 
    def delete(self, id):
 
        """DELETE /users/id: Delete an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="DELETE" />
 
        # Or using helpers:
 
        #    h.form(url('user', id=ID),
 
        #           method='delete')
 
        # url('user', id=ID)
 
        user_model = UserModel()
 
        try:
 
            user_model.delete(id)
 
            h.flash(_('sucessfully deleted user'), category='success')
 
        except DefaultUserException, e:
 
        except (UserOwnsReposException, DefaultUserException), e:
 
            h.flash(str(e), category='warning')
 
        except Exception:
 
            h.flash(_('An error occured during deletion of user'),
 
                    category='error')
 
        return redirect(url('users'))
 

	
 
    def show(self, id, format='html'):
 
        """GET /users/id: Show a specific item"""
 
        # url('user', id=ID)
 

	
 

	
 
    def edit(self, id, format='html'):
rhodecode/lib/auth.py
Show inline comments
 
@@ -15,26 +15,27 @@
 
# 
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on April 4, 2010
 

	
 
@author: marcink
 
"""
 
from pylons import config, session, url, request
 
from pylons.controllers.util import abort, redirect
 
from rhodecode.lib.exceptions import *
 
from rhodecode.lib.utils import get_repo_slug
 
from rhodecode.lib.auth_ldap import AuthLdap, UsernameError, PasswordError
 
from rhodecode.lib.auth_ldap import AuthLdap
 
from rhodecode.model import meta
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
 
    UserToPerm
 
import bcrypt
 
from decorator import decorator
 
import logging
 
import random
 
import traceback
 

	
 
log = logging.getLogger(__name__)
 
@@ -120,25 +121,25 @@ def authfunc(environ, username, password
 
                  }
 
            log.debug('Checking for ldap authentication')
 
            try:
 
                aldap = AuthLdap(**kwargs)
 
                res = aldap.authenticate_ldap(username, password)
 

	
 
                authenticated = res[1]['uid'][0] == username
 

	
 
                if authenticated and user_model.create_ldap(username, password):
 
                    log.info('created new ldap user')
 

	
 
                return authenticated
 
            except (UsernameError, PasswordError):
 
            except (LdapUsernameError, LdapPasswordError):
 
                return False
 
            except:
 
                log.error(traceback.format_exc())
 
                return False
 
    return False
 

	
 
class  AuthUser(object):
 
    """
 
    A simple object that handles a mercurial username for authentication
 
    """
 
    def __init__(self):
 
        self.username = 'None'
rhodecode/lib/auth_ldap.py
Show inline comments
 
#==============================================================================
 
# LDAP
 
#Name     = Just a description for the auth modes page
 
#Host     = DepartmentName.OrganizationName.local/ IP
 
#Port     = 389 default for ldap
 
#LDAPS    = no set True if You need to use ldaps
 
#Account  = DepartmentName\UserName (or UserName@MyDomain depending on AD server)
 
#Password = <password>
 
#Base DN  = DC=DepartmentName,DC=OrganizationName,DC=local
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# ldap authentication lib
 
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
#
 
# This program is free software; you can redistribute it and/or
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# 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 General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on Nov 17, 2010
 

	
 
#==============================================================================
 
@author: marcink
 
"""
 

	
 
from rhodecode.lib.exceptions import LdapImportError, UsernameError, \
 
    PasswordError, ConnectionError
 
from rhodecode.lib.exceptions import *
 
import logging
 

	
 
log = logging.getLogger(__name__)
 

	
 
try:
 
    import ldap
 
except ImportError:
 
    pass
 

	
 
class AuthLdap(object):
 

	
 
    def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='',
 
@@ -52,42 +64,42 @@ class AuthLdap(object):
 
        EnvironmentError if the LDAP server can't be reached.
 
        
 
        :param username: username
 
        :param password: password
 
        """
 

	
 
        from rhodecode.lib.helpers import chop_at
 

	
 
        uid = chop_at(username, "@%s" % self.LDAP_SERVER_ADDRESS)
 
        dn = self.AUTH_DN % (uid, self.BASE_DN)
 
        log.debug("Authenticating %r at %s", dn, self.LDAP_SERVER)
 
        if "," in username:
 
            raise UsernameError("invalid character in username: ,")
 
            raise LdapUsernameError("invalid character in username: ,")
 
        try:
 
            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, '/etc/openldap/cacerts')
 
            ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10)
 
            server = ldap.initialize(self.LDAP_SERVER)
 
            if self.ldap_version == 2:
 
                server.protocol = ldap.VERSION2
 
            else:
 
                server.protocol = ldap.VERSION3
 

	
 
            if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
 
                server.simple_bind_s(self.AUTH_DN % (self.LDAP_BIND_DN,
 
                                                self.BASE_DN),
 
                                                self.LDAP_BIND_PASS)
 

	
 
            server.simple_bind_s(dn, password)
 
            properties = server.search_s(dn, ldap.SCOPE_SUBTREE)
 
            if not properties:
 
                raise ldap.NO_SUCH_OBJECT()
 
        except ldap.NO_SUCH_OBJECT, e:
 
            log.debug("LDAP says no such user '%s' (%s)", uid, username)
 
            raise UsernameError()
 
            raise LdapUsernameError()
 
        except ldap.INVALID_CREDENTIALS, e:
 
            log.debug("LDAP rejected password for user '%s' (%s)", uid, username)
 
            raise PasswordError()
 
            raise LdapPasswordError()
 
        except ldap.SERVER_DOWN, e:
 
            raise ConnectionError("LDAP can't access authentication server")
 
            raise LdapConnectionError("LDAP can't access authentication server")
 

	
 
        return properties[0]
 

	
rhodecode/lib/exceptions.py
Show inline comments
 
@@ -14,16 +14,19 @@
 
# GNU General Public License for more details.
 
# 
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on Nov 17, 2010
 
Custom Exceptions modules
 
@author: marcink
 
"""
 

	
 
class UsernameError(Exception):pass
 
class PasswordError(Exception):pass
 
class ConnectionError(Exception):pass
 
class LdapUsernameError(Exception):pass
 
class LdapPasswordError(Exception):pass
 
class LdapConnectionError(Exception):pass
 
class LdapImportError(Exception):pass
 

	
 
class DefaultUserException(Exception):pass
 
class UserOwnsReposException(Exception):pass
rhodecode/model/db.py
Show inline comments
 
@@ -39,24 +39,26 @@ class User(Base):
 
    password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
 
    admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=False)
 
    name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
 
    is_ldap = Column("is_ldap", BOOLEAN(), nullable=False, unique=None, default=False)
 

	
 
    user_log = relation('UserLog', cascade='all')
 
    user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
 

	
 
    repositories = relation('Repository')
 

	
 
    @LazyProperty
 
    def full_contact(self):
 
        return '%s %s <%s>' % (self.name, self.lastname, self.email)
 

	
 
    def __repr__(self):
 
        return "<User('id:%s:%s')>" % (self.user_id, self.username)
 

	
 
    def update_lastlogin(self):
 
        """Update user lastlogin"""
 
        import datetime
 

	
 
        try:
rhodecode/model/user.py
Show inline comments
 
@@ -18,30 +18,31 @@
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on April 9, 2010
 
Model for users
 
:author: marcink
 
"""
 

	
 
from pylons.i18n.translation import _
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import User
 
from rhodecode.model.meta import Session
 
from rhodecode.lib.exceptions import *
 
import logging
 
import traceback
 

	
 
log = logging.getLogger(__name__)
 

	
 
class DefaultUserException(Exception):pass
 

	
 

	
 
class UserModel(object):
 

	
 
    def __init__(self):
 
        self.sa = Session()
 

	
 
    def get(self, user_id, cache=False):
 
        user = self.sa.query(User)
 
        if cache:
 
            user = user.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % user_id))
 
        return user.get(user_id)
 
@@ -119,24 +120,25 @@ class UserModel(object):
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def update(self, user_id, form_data):
 
        try:
 
            new_user = self.get(user_id, cache=False)
 
            if new_user.username == 'default':
 
                raise DefaultUserException(
 
                                _("You can't Edit this user since it's"
 
                                  " crucial for entire application"))
 

	
 
            for k, v in form_data.items():
 
                if k == 'new_password' and v != '':
 
                    new_user.password = v
 
                else:
 
                    setattr(new_user, k, v)
 

	
 
            self.sa.add(new_user)
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 
@@ -160,24 +162,30 @@ class UserModel(object):
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def delete(self, user_id):
 
        try:
 
            user = self.get(user_id, cache=False)
 
            if user.username == 'default':
 
                raise DefaultUserException(
 
                                _("You can't remove this user since it's"
 
                                  " crucial for entire application"))
 
            if user.repositories:
 
                raise UserOwnsReposException(_('This user still owns %s '
 
                                               'repositories and cannot be '
 
                                               'removed. Switch owners or '
 
                                               'remove those repositories') \
 
                                               % user.repositories)
 
            self.sa.delete(user)
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def reset_password(self, data):
 
        from rhodecode.lib.celerylib import tasks, run_task
 
        run_task(tasks.reset_user_password, data['email'])
 

	
 

	
0 comments (0 inline, 0 general)