changeset 3146:c5169e445fb8 beta

Full IP restrictions enabled - short cache query for IP for performance - remove redundant logic - some small css fixes for login form to better show IP restricted message
author Marcin Kuzminski <marcin@python-works.com>
date Fri, 04 Jan 2013 23:34:53 +0100
parents bee09f317edc
children 8182ebed2922
files rhodecode/controllers/api/__init__.py rhodecode/controllers/login.py rhodecode/lib/auth.py rhodecode/lib/base.py rhodecode/model/db.py rhodecode/model/user.py rhodecode/public/css/style.css
diffstat 7 files changed, 46 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/controllers/api/__init__.py	Fri Jan 04 00:24:22 2013 +0100
+++ b/rhodecode/controllers/api/__init__.py	Fri Jan 04 23:34:53 2013 +0100
@@ -43,7 +43,7 @@
 HTTPBadRequest, HTTPError
 
 from rhodecode.model.db import User
-from rhodecode.lib.auth import AuthUser, check_ip_access
+from rhodecode.lib.auth import AuthUser
 from rhodecode.lib.base import _get_ip_addr, _get_access_path
 from rhodecode.lib.utils2 import safe_unicode
 
@@ -148,17 +148,15 @@
             if u is None:
                 return jsonrpc_error(retid=self._req_id,
                                      message='Invalid API KEY')
+
             #check if we are allowed to use this IP
-            allowed_ips = AuthUser.get_allowed_ips(u.user_id)
-            if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips) is False:
-                log.info('Access for IP:%s forbidden, '
-                         'not in %s' % (ip_addr, allowed_ips))
+            auth_u = AuthUser(u.user_id, self._req_api_key, ip_addr=ip_addr)
+            if not auth_u.ip_allowed:
                 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))
 
-            auth_u = AuthUser(u.user_id, self._req_api_key, ip_addr=ip_addr)
         except Exception, e:
             return jsonrpc_error(retid=self._req_id,
                                  message='Invalid API KEY')
--- a/rhodecode/controllers/login.py	Fri Jan 04 00:24:22 2013 +0100
+++ b/rhodecode/controllers/login.py	Fri Jan 04 23:34:53 2013 +0100
@@ -54,10 +54,9 @@
     def index(self):
         # redirect if already logged in
         c.came_from = request.GET.get('came_from')
-
-        if self.rhodecode_user.is_authenticated \
-                            and self.rhodecode_user.username != 'default':
-
+        not_default = self.rhodecode_user.username != 'default'
+        ip_allowed = self.rhodecode_user.ip_allowed
+        if self.rhodecode_user.is_authenticated and not_default and ip_allowed:
             return redirect(url('home'))
 
         if request.POST:
--- a/rhodecode/lib/auth.py	Fri Jan 04 00:24:22 2013 +0100
+++ b/rhodecode/lib/auth.py	Fri Jan 04 23:34:53 2013 +0100
@@ -46,6 +46,7 @@
 from rhodecode.model import meta
 from rhodecode.model.user import UserModel
 from rhodecode.model.db import Permission, RhodeCodeSetting, User, UserIpMap
+from rhodecode.lib.caching_query import FromCache
 
 log = logging.getLogger(__name__)
 
@@ -327,7 +328,6 @@
         self.admin = False
         self.inherit_default_permissions = False
         self.permissions = {}
-        self.allowed_ips = set()
         self._api_key = api_key
         self.propagate_data()
         self._instance = None
@@ -377,13 +377,29 @@
 
         log.debug('Auth User is now %s' % self)
         user_model.fill_perms(self)
-        log.debug('Filling Allowed IPs')
-        self.allowed_ips = AuthUser.get_allowed_ips(self.user_id)
 
     @property
     def is_admin(self):
         return self.admin
 
+    @property
+    def ip_allowed(self):
+        """
+        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
+        """
+        #check IP
+        allowed_ips = AuthUser.get_allowed_ips(self.user_id, cache=True)
+        if check_ip_access(source_ip=self.ip_addr, allowed_ips=allowed_ips):
+            log.debug('IP:%s is in range of %s' % (self.ip_addr, allowed_ips))
+            return True
+        else:
+            log.info('Access for IP:%s forbidden, '
+                     'not in %s' % (self.ip_addr, allowed_ips))
+            return False
+
     def __repr__(self):
         return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
                                               self.is_authenticated)
@@ -411,9 +427,12 @@
         return AuthUser(user_id, api_key, username)
 
     @classmethod
-    def get_allowed_ips(cls, user_id):
+    def get_allowed_ips(cls, user_id, cache=False):
         _set = set()
-        user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id).all()
+        user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
+        if cache:
+            user_ips = user_ips.options(FromCache("sql_cache_short",
+                                                  "get_user_ips_%s" % user_id))
         for ip in user_ips:
             _set.add(ip.ip_addr)
         return _set or set(['0.0.0.0/0'])
@@ -462,6 +481,15 @@
     def __wrapper(self, func, *fargs, **fkwargs):
         cls = fargs[0]
         user = cls.rhodecode_user
+        loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
+
+        #check IP
+        ip_access_ok = True
+        if not user.ip_allowed:
+            from rhodecode.lib import helpers as h
+            h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr))),
+                    category='warning')
+            ip_access_ok = False
 
         api_access_ok = False
         if self.api_access:
@@ -470,9 +498,9 @@
                 api_access_ok = True
             else:
                 log.debug("API KEY token not valid")
-        loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
+
         log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
-        if user.is_authenticated or api_access_ok:
+        if (user.is_authenticated or api_access_ok) and ip_access_ok:
             reason = 'RegularAuth' if user.is_authenticated else 'APIAuth'
             log.info('user %s is authenticated and granted access to %s '
                      'using %s' % (user.username, loc, reason)
--- a/rhodecode/lib/base.py	Fri Jan 04 00:24:22 2013 +0100
+++ b/rhodecode/lib/base.py	Fri Jan 04 23:34:53 2013 +0100
@@ -20,7 +20,7 @@
 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, check_ip_access
+    HasPermissionAnyMiddleware, CookieStoreWrapper
 from rhodecode.lib.utils import get_repo_slug, invalidate_cache
 from rhodecode.model import meta
 
@@ -146,10 +146,8 @@
         :param repo_name: repository name
         """
         #check IP
-        allowed_ips = AuthUser.get_allowed_ips(user.user_id)
-        if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips) is False:
-            log.info('Access for IP:%s forbidden, '
-                     'not in %s' % (ip_addr, allowed_ips))
+        authuser = AuthUser(user_id=user.user_id, ip_addr=ip_addr)
+        if not authuser.ip_allowed:
             return False
         else:
             log.info('Access for IP:%s allowed' % (ip_addr))
--- a/rhodecode/model/db.py	Fri Jan 04 00:24:22 2013 +0100
+++ b/rhodecode/model/db.py	Fri Jan 04 23:34:53 2013 +0100
@@ -536,6 +536,7 @@
     ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
     ip_addr = Column("ip_addr", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
+    active = Column("active", Boolean(), nullable=True, unique=None, default=True)
     user = relationship('User', lazy='joined')
 
     @classmethod
--- a/rhodecode/model/user.py	Fri Jan 04 00:24:22 2013 +0100
+++ b/rhodecode/model/user.py	Fri Jan 04 23:34:53 2013 +0100
@@ -27,7 +27,6 @@
 import traceback
 import itertools
 import collections
-import functools
 from pylons import url
 from pylons.i18n.translation import _
 
--- a/rhodecode/public/css/style.css	Fri Jan 04 00:24:22 2013 +0100
+++ b/rhodecode/public/css/style.css	Fri Jan 04 23:34:53 2013 +0100
@@ -2002,7 +2002,6 @@
 }
 
 #login div.title {
-	width: 420px;
 	clear: both;
 	overflow: hidden;
 	position: relative;
@@ -2021,7 +2020,6 @@
 }
 
 #login div.inner {
-	width: 380px;
 	background: #FFF url("../images/login.png") no-repeat top left;
 	border-top: none;
 	border-bottom: none;
@@ -2038,7 +2036,6 @@
 }
 
 #login div.form div.fields div.field div.input input {
-	width: 176px;
 	background: #FFF;
 	border-top: 1px solid #b3b3b3;
 	border-left: 1px solid #b3b3b3;