Changeset - 4a2a66bf93c5
[Not reviewed]
default
0 8 0
Søren Løvborg - 10 years ago 2015-06-26 20:36:05
kwi@kwi.dk
AuthUser: Drop ip_addr field

None of the AuthUser consumers actually need to get the IP address from
the AuthUser object, so it's just redundant.

Also, AuthUser represents a user session, and should not be used as a
generic user + IP address data structure.
8 files changed with 33 insertions and 35 deletions:
0 comments (0 inline, 0 general)
kallithea/controllers/admin/my_account.py
Show inline comments
 
@@ -89,26 +89,26 @@ class MyAccountController(BaseController
 
        repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
 
                                                   admin=admin)
 
        #json used to render the grid
 
        return json.dumps(repos_data)
 

	
 
    def my_account(self):
 
        """
 
        GET /_admin/my_account Displays info about my account
 
        """
 
        # url('my_account')
 
        c.active = 'profile'
 
        self.__load_data()
 
        c.perm_user = AuthUser(user_id=self.authuser.user_id,
 
                               ip_addr=self.ip_addr)
 
        c.perm_user = AuthUser(user_id=self.authuser.user_id)
 
        c.ip_addr = self.ip_addr
 
        c.extern_type = c.user.extern_type
 
        c.extern_name = c.user.extern_name
 

	
 
        defaults = c.user.get_dict()
 
        update = False
 
        if request.POST:
 
            _form = UserForm(edit=True,
 
                             old_data={'user_id': self.authuser.user_id,
 
                                       'email': self.authuser.email})()
 
            form_result = {}
 
            try:
 
                post_data = dict(request.POST)
 
@@ -184,26 +184,26 @@ class MyAccountController(BaseController
 

	
 
    def my_account_watched(self):
 
        c.active = 'watched'
 
        self.__load_data()
 

	
 
        #json used to render the grid
 
        c.data = self._load_my_repos_data(watched=True)
 
        return render('admin/my_account/my_account.html')
 

	
 
    def my_account_perms(self):
 
        c.active = 'perms'
 
        self.__load_data()
 
        c.perm_user = AuthUser(user_id=self.authuser.user_id,
 
                               ip_addr=self.ip_addr)
 
        c.perm_user = AuthUser(user_id=self.authuser.user_id)
 
        c.ip_addr = self.ip_addr
 

	
 
        return render('admin/my_account/my_account.html')
 

	
 
    def my_account_emails(self):
 
        c.active = 'emails'
 
        self.__load_data()
 

	
 
        c.user_email_map = UserEmailMap.query()\
 
            .filter(UserEmailMap.user == c.user).all()
 
        return render('admin/my_account/my_account.html')
 

	
 
    def my_account_emails_add(self):
kallithea/controllers/admin/users.py
Show inline comments
 
@@ -159,25 +159,26 @@ class UsersController(BaseController):
 
        """PUT /users/id: Update an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="PUT" />
 
        # Or using helpers:
 
        #    h.form(url('update_user', id=ID),
 
        #           method='put')
 
        # url('user', id=ID)
 
        c.active = 'profile'
 
        user_model = UserModel()
 
        c.user = user_model.get(id)
 
        c.extern_type = c.user.extern_type
 
        c.extern_name = c.user.extern_name
 
        c.perm_user = AuthUser(user_id=id, ip_addr=self.ip_addr)
 
        c.perm_user = AuthUser(user_id=id)
 
        c.ip_addr = self.ip_addr
 
        _form = UserForm(edit=True, old_data={'user_id': id,
 
                                              'email': c.user.email})()
 
        form_result = {}
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            skip_attrs = ['extern_type', 'extern_name']
 
            #TODO: plugin should define if username can be updated
 
            if c.extern_type != kallithea.EXTERN_TYPE_INTERNAL:
 
                # forbid updating username for external accounts
 
                skip_attrs.append('username')
 

	
 
            user_model.update(id, form_result, skip_attrs=skip_attrs)
 
@@ -239,37 +240,39 @@ class UsersController(BaseController):
 
            return User.get_or_404(id, allow_default=False)
 
        except DefaultUserException:
 
            h.flash(_("The default user cannot be edited"), category='warning')
 
            raise HTTPNotFound
 

	
 
    def edit(self, id, format='html'):
 
        """GET /users/id/edit: Form to edit an existing item"""
 
        # url('edit_user', id=ID)
 
        c.user = self._get_user_or_raise_if_default(id)
 
        c.active = 'profile'
 
        c.extern_type = c.user.extern_type
 
        c.extern_name = c.user.extern_name
 
        c.perm_user = AuthUser(user_id=id, ip_addr=self.ip_addr)
 
        c.perm_user = AuthUser(user_id=id)
 
        c.ip_addr = self.ip_addr
 

	
 
        defaults = c.user.get_dict()
 
        return htmlfill.render(
 
            render('admin/users/user_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    def edit_advanced(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 
        c.active = 'advanced'
 
        c.perm_user = AuthUser(user_id=id, ip_addr=self.ip_addr)
 
        c.perm_user = AuthUser(user_id=id)
 
        c.ip_addr = self.ip_addr
 

	
 
        umodel = UserModel()
 
        defaults = c.user.get_dict()
 
        defaults.update({
 
            'create_repo_perm': umodel.has_perm(c.user, 'hg.create.repository'),
 
            'create_user_group_perm': umodel.has_perm(c.user,
 
                                                      'hg.usergroup.create.true'),
 
            'fork_repo_perm': umodel.has_perm(c.user, 'hg.fork.repository'),
 
        })
 
        return htmlfill.render(
 
            render('admin/users/user_edit.html'),
 
            defaults=defaults,
 
@@ -322,25 +325,26 @@ class UsersController(BaseController):
 
            ApiKeyModel().delete(api_key, c.user.user_id)
 
            Session().commit()
 
            h.flash(_("API key successfully deleted"), category='success')
 

	
 
        return redirect(url('edit_user_api_keys', id=c.user.user_id))
 

	
 
    def update_account(self, id):
 
        pass
 

	
 
    def edit_perms(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 
        c.active = 'perms'
 
        c.perm_user = AuthUser(user_id=id, ip_addr=self.ip_addr)
 
        c.perm_user = AuthUser(user_id=id)
 
        c.ip_addr = self.ip_addr
 

	
 
        umodel = UserModel()
 
        defaults = c.user.get_dict()
 
        defaults.update({
 
            'create_repo_perm': umodel.has_perm(c.user, 'hg.create.repository'),
 
            'create_user_group_perm': umodel.has_perm(c.user,
 
                                                      'hg.usergroup.create.true'),
 
            'fork_repo_perm': umodel.has_perm(c.user, 'hg.fork.repository'),
 
        })
 
        return htmlfill.render(
 
            render('admin/users/user_edit.html'),
 
            defaults=defaults,
kallithea/controllers/api/__init__.py
Show inline comments
 
@@ -150,26 +150,26 @@ class JSONRPCController(WSGIController):
 
        except KeyError, e:
 
            return jsonrpc_error(retid=self._req_id,
 
                                 message='Incorrect JSON query missing %s' % e)
 

	
 
        # check if we can find this session using api_key
 
        try:
 
            u = User.get_by_api_key(self._req_api_key)
 
            if u is None:
 
                return jsonrpc_error(retid=self._req_id,
 
                                     message='Invalid API key')
 

	
 
            #check if we are allowed to use this IP
 
            auth_u = AuthUser(u.user_id, self._req_api_key, ip_addr=ip_addr)
 
            if not auth_u.ip_allowed:
 
            auth_u = AuthUser(u.user_id, self._req_api_key)
 
            if not auth_u.is_ip_allowed(ip_addr):
 
                return jsonrpc_error(retid=self._req_id,
 
                        message='request from IP:%s not allowed' % (ip_addr,))
 
            else:
 
                log.info('Access for IP:%s allowed' % (ip_addr,))
 

	
 
        except Exception, e:
 
            return jsonrpc_error(retid=self._req_id,
 
                                 message='Invalid API key')
 

	
 
        self._error = None
 
        try:
 
            self._func = self._find_method()
kallithea/controllers/login.py
Show inline comments
 
@@ -100,25 +100,25 @@ class LoginController(BaseController):
 

	
 
    def _redirect_to_origin(self, origin):
 
        '''redirect to the original page, preserving any get arguments given'''
 
        request.GET.pop('came_from', None)
 
        raise HTTPFound(location=url(origin, **request.GET))
 

	
 
    def index(self):
 
        c.came_from = safe_str(request.GET.get('came_from', ''))
 
        if not self._validate_came_from(c.came_from):
 
            c.came_from = url('home')
 

	
 
        not_default = self.authuser.username != User.DEFAULT_USER
 
        ip_allowed = self.authuser.ip_allowed
 
        ip_allowed = self.authuser.is_ip_allowed(self.ip_addr)
 

	
 
        # redirect if already logged in
 
        if self.authuser.is_authenticated and not_default and ip_allowed:
 
            return self._redirect_to_origin(c.came_from)
 

	
 
        if request.POST:
 
            # import Login Form validator class
 
            login_form = LoginForm()
 
            try:
 
                session.invalidate()
 
                c.form_result = login_form.to_python(dict(request.POST))
 
                # form checks for username/password, now we're authenticated
kallithea/lib/auth.py
Show inline comments
 
@@ -459,32 +459,31 @@ def allowed_api_access(controller_name, 
 
    return api_access_valid
 

	
 

	
 
class AuthUser(object):
 
    """
 
    A simple object that handles all attributes of user in Kallithea
 

	
 
    It does lookup based on API key,given user, or user present in session
 
    Then it fills all required information for such user. It also checks if
 
    anonymous access is enabled and if so, it returns default user as logged in
 
    """
 

	
 
    def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
 
    def __init__(self, user_id=None, api_key=None, username=None):
 

	
 
        self.user_id = user_id
 
        self._api_key = api_key
 

	
 
        self.api_key = None
 
        self.username = username
 
        self.ip_addr = ip_addr
 
        self.name = ''
 
        self.lastname = ''
 
        self.email = ''
 
        self.is_authenticated = False
 
        self.admin = False
 
        self.inherit_default_permissions = False
 

	
 
        self.propagate_data()
 
        self._instance = None
 

	
 
    @LazyProperty
 
    def permissions(self):
 
@@ -587,52 +586,48 @@ class AuthUser(object):
 
        """
 
        return [x[0] for x in self.permissions['repositories_groups'].iteritems()
 
                if x[1] == 'group.admin']
 

	
 
    @property
 
    def user_groups_admin(self):
 
        """
 
        Returns list of user groups you're an admin of
 
        """
 
        return [x[0] for x in self.permissions['user_groups'].iteritems()
 
                if x[1] == 'usergroup.admin']
 

	
 
    @property
 
    def ip_allowed(self):
 
    def is_ip_allowed(self, ip_addr):
 
        """
 
        Checks if ip_addr used in constructor is allowed from defined list of
 
        allowed ip_addresses for user
 

	
 
        :returns: boolean, True if ip is in allowed ip range
 
        Determine if `ip_addr` is on the list of allowed IP addresses
 
        for this user.
 
        """
 
        # check IP
 
        inherit = self.inherit_default_permissions
 
        return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
 
        return AuthUser.check_ip_allowed(self.user_id, ip_addr,
 
                                         inherit_from_default=inherit)
 

	
 
    @classmethod
 
    def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
 
        allowed_ips = AuthUser.get_allowed_ips(user_id, cache=True,
 
                        inherit_from_default=inherit_from_default)
 
        if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
 
            log.debug('IP:%s is in range of %s' % (ip_addr, allowed_ips))
 
            return True
 
        else:
 
            log.info('Access for IP:%s forbidden, '
 
                     'not in %s' % (ip_addr, allowed_ips))
 
            return False
 

	
 
    def __repr__(self):
 
        return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
 
            % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
 
        return "<AuthUser('id:%s[%s] auth:%s')>"\
 
            % (self.user_id, self.username, self.is_authenticated)
 

	
 
    def set_authenticated(self, authenticated=True):
 
        if self.user_id != self.anonymous_user.user_id:
 
            self.is_authenticated = authenticated
 

	
 
    def get_cookie_store(self):
 
        return {'username': self.username,
 
                'user_id': self.user_id,
 
                'is_authenticated': self.is_authenticated}
 

	
 
    @classmethod
 
    def from_cookie_store(cls, cookie_store):
 
@@ -720,32 +715,32 @@ class LoginRequired(object):
 

	
 
    :param api_access: if enabled this checks only for valid auth token
 
        and grants access based on valid token
 
    """
 

	
 
    def __init__(self, api_access=False):
 
        self.api_access = api_access
 

	
 
    def __call__(self, func):
 
        return decorator(self.__wrapper, func)
 

	
 
    def __wrapper(self, func, *fargs, **fkwargs):
 
        cls = fargs[0]
 
        user = cls.authuser
 
        loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
 
        controller = fargs[0]
 
        user = controller.authuser
 
        loc = "%s:%s" % (controller.__class__.__name__, func.__name__)
 
        log.debug('Checking access for user %s @ %s' % (user, loc))
 

	
 
        # check if our IP is allowed
 
        if not user.ip_allowed:
 
            return redirect_to_login(_('IP %s not allowed' % (user.ip_addr)))
 
        if not user.is_ip_allowed(controller.ip_addr):
 
            return redirect_to_login(_('IP %s not allowed') % controller.ip_addr)
 

	
 
        # check if we used an API key and it's a valid one
 
        api_key = request.GET.get('api_key')
 
        if api_key is not None:
 
            # explicit controller is enabled or API is in our whitelist
 
            if self.api_access or allowed_api_access(loc, api_key=api_key):
 
                if api_key in user.api_keys:
 
                    log.info('user %s authenticated with API key ****%s @ %s'
 
                             % (user, api_key[-4:], loc))
 
                    return func(*fargs, **fkwargs)
 
                else:
 
                    log.warning('API key ****%s is NOT valid' % api_key[-4:])
kallithea/lib/base.py
Show inline comments
 
@@ -333,69 +333,68 @@ class BaseController(WSGIController):
 
        c.backends = BACKENDS.keys()
 
        c.unread_notifications = NotificationModel()\
 
                        .get_unread_cnt_for_user(c.authuser.user_id)
 

	
 
        self.cut_off_limit = safe_int(config.get('cut_off_limit'))
 

	
 
        c.my_pr_count = PullRequestModel().get_pullrequest_cnt_for_user(c.authuser.user_id)
 

	
 
        self.sa = meta.Session
 
        self.scm_model = ScmModel(self.sa)
 

	
 
    @staticmethod
 
    def _determine_auth_user(ip_addr, api_key, session_authuser):
 
    def _determine_auth_user(api_key, session_authuser):
 
        """
 
        Create an `AuthUser` object given the IP address of the request, the
 
        API key (if any), and the authuser from the session.
 
        """
 

	
 
        if api_key:
 
            # when using API_KEY we are sure user exists.
 
            auth_user = AuthUser(api_key=api_key, ip_addr=ip_addr)
 
            auth_user = AuthUser(api_key=api_key)
 
            authenticated = False
 
        else:
 
            cookie_store = CookieStoreWrapper(session_authuser)
 
            user_id = cookie_store.get('user_id')
 
            try:
 
                auth_user = AuthUser(user_id=user_id, ip_addr=ip_addr)
 
                auth_user = AuthUser(user_id=user_id)
 
            except UserCreationError as e:
 
                # container auth or other auth functions that create users on
 
                # the fly can throw UserCreationError to signal issues with
 
                # user creation. Explanation should be provided in the
 
                # exception object.
 
                from kallithea.lib import helpers as h
 
                h.flash(e, 'error')
 
                auth_user = AuthUser(ip_addr=ip_addr)
 
                auth_user = AuthUser()
 

	
 
            authenticated = cookie_store.get('is_authenticated')
 

	
 
        if not auth_user.is_authenticated and auth_user.user_id is not None:
 
            # user is not authenticated and not empty
 
            auth_user.set_authenticated(authenticated)
 

	
 
        return auth_user
 

	
 
    def __call__(self, environ, start_response):
 
        """Invoke the Controller"""
 

	
 
        # WSGIController.__call__ dispatches to the Controller method
 
        # the request is routed to. This routing information is
 
        # available in environ['pylons.routes_dict']
 
        try:
 
            self.ip_addr = _get_ip_addr(environ)
 
            # make sure that we update permissions each time we call controller
 

	
 
            #set globals for auth user
 
            self.authuser = c.authuser = request.user = self._determine_auth_user(
 
                self.ip_addr,
 
                request.GET.get('api_key'),
 
                session.get('authuser'),
 
            )
 

	
 
            log.info('IP: %s User: %s accessed %s',
 
                self.ip_addr, self.authuser,
 
                safe_unicode(_get_access_path(environ)),
 
            )
 
            return WSGIController.__call__(self, environ, start_response)
 
        finally:
 
            meta.Session.remove()
 

	
kallithea/templates/admin/my_account/my_account_profile.html
Show inline comments
 
@@ -4,25 +4,25 @@ ${h.form(url('my_account'), method='post
 
         <div class="field">
 
           <div class="gravatar_box">
 
               <div class="gravatar">
 
                 ${h.gravatar(c.user.email)}
 
               </div>
 
                <p>
 
                %if c.visual.use_gravatar:
 
                <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong>
 
                <br/>${_('Using')} ${c.user.email}
 
                %else:
 
                <strong>${_('Avatars are disabled')}</strong>
 
                <br/>${c.user.email or _('Missing email, please update your user email address.')}
 
                    [${_('Current IP')}: ${c.perm_user.ip_addr or "?"}]
 
                    [${_('Current IP')}: ${c.ip_addr}]
 
                %endif
 
               </p>
 
           </div>
 
         </div>
 

	
 
        <% readonly = None %>
 
        <% disabled = "" %>
 
        <div class="fields">
 
           %if c.extern_type != c.EXTERN_TYPE_INTERNAL:
 
                <% readonly = "readonly" %>
 
                <% disabled = " disabled" %>
 
                <strong>${_('Your user is in an external Source of Record; some details cannot be managed here')}.</strong>
kallithea/templates/admin/users/user_edit_profile.html
Show inline comments
 
@@ -3,25 +3,25 @@ ${h.form(url('update_user', id=c.user.us
 
        <div class="field">
 
           <div class="gravatar_box">
 
                <div class="gravatar">${h.gravatar(c.user.email)}</div>
 
                <p>
 
                %if c.visual.use_gravatar:
 
                <strong>${_('Change avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong>
 
                <br/>${_('Using')} ${c.user.email}
 
                %else:
 
                <strong>${_('Avatars are disabled')}</strong>
 
                <br/>${c.user.email or _('Missing email, please update this user email address.')}
 
                        ##show current ip just if we show ourself
 
                        %if c.authuser.username == c.user.username:
 
                            [${_('Current IP')}: ${c.perm_user.ip_addr or "?"}]
 
                            [${_('Current IP')}: ${c.ip_addr}]
 
                        %endif
 
                %endif
 
           </div>
 
        </div>
 
        <% readonly = None %>
 
        <% disabled = "" %>
 
        <div class="fields">
 
            %if c.extern_type != c.EXTERN_TYPE_INTERNAL:
 
             <div class="field">
 
               <% readonly = "readonly" %>
 
               <% disabled = " disabled" %>
 
               <strong>${_('This user is in an external Source of Record (%s); some details cannot be managed here.' % c.extern_type)}.</strong>
0 comments (0 inline, 0 general)