diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py --- a/rhodecode/lib/auth.py +++ b/rhodecode/lib/auth.py @@ -34,6 +34,7 @@ from decorator import decorator from pylons import config, url, request from pylons.controllers.util import abort, redirect from pylons.i18n.translation import _ +from sqlalchemy.orm.exc import ObjectDeletedError from rhodecode import __platform__, is_windows, is_unix from rhodecode.model.meta import Session @@ -447,8 +448,13 @@ class AuthUser(object): 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']) + try: + _set.add(ip.ip_addr) + except ObjectDeletedError: + # since we use heavy caching sometimes it happens that we get + # deleted objects here, we just skip them + pass + return _set or set(['0.0.0.0/0', '::/0']) def set_available_permissions(config): @@ -990,6 +996,13 @@ def check_ip_access(source_ip, allowed_i log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips)) if isinstance(allowed_ips, (tuple, list, set)): for ip in allowed_ips: - if ipaddr.IPAddress(source_ip) in ipaddr.IPNetwork(ip): - return True + try: + if ipaddr.IPAddress(source_ip) in ipaddr.IPNetwork(ip): + return True + # for any case we cannot determine the IP, don't crash just + # skip it and log as error, we want to say forbidden still when + # sending bad IP + except Exception: + log.error(traceback.format_exc()) + continue return False diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -562,7 +562,7 @@ class UserIpMap(Base, BaseModel): @classmethod def _get_ip_range(cls, ip_addr): from rhodecode.lib import ipaddr - net = ipaddr.IPv4Network(ip_addr) + net = ipaddr.IPNetwork(address=ip_addr) return [str(net.network), str(net.broadcast)] def __json__(self): diff --git a/rhodecode/model/validators.py b/rhodecode/model/validators.py --- a/rhodecode/model/validators.py +++ b/rhodecode/model/validators.py @@ -14,6 +14,7 @@ from formencode.validators import ( NotEmpty, IPAddress, CIDR ) from rhodecode.lib.compat import OrderedSet +from rhodecode.lib import ipaddr from rhodecode.lib.utils import repo_name_slug from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User,\ ChangesetStatus @@ -711,35 +712,31 @@ def NotReviewedRevisions(repo_id): def ValidIp(): class _validator(CIDR): messages = dict( - badFormat=_('Please enter a valid IP address (a.b.c.d)'), - illegalOctets=_('The octets must be within the range of 0-255' - ' (not %(octet)r)'), + badFormat=_('Please enter a valid IPv4 or IpV6 address'), illegalBits=_('The network size (bits) must be within the range' ' of 0-32 (not %(bits)r)')) + def to_python(self, value, state): + v = super(_validator, self).to_python(value, state) + v = v.strip() + net = ipaddr.IPNetwork(address=v) + if isinstance(net, ipaddr.IPv4Network): + #if IPv4 doesn't end with a mask, add /32 + if '/' not in value: + v += '/32' + if isinstance(net, ipaddr.IPv6Network): + #if IPv6 doesn't end with a mask, add /128 + if '/' not in value: + v += '/128' + return v + def validate_python(self, value, state): try: - # Split into octets and bits - if '/' in value: # a.b.c.d/e - addr, bits = value.split('/') - else: # a.b.c.d - addr, bits = value, 32 - # Use IPAddress validator to validate the IP part - IPAddress.validate_python(self, addr, state) - # Bits (netmask) correct? - if not 0 <= int(bits) <= 32: - raise formencode.Invalid( - self.message('illegalBits', state, bits=bits), - value, state) - # Splitting faild: wrong syntax + addr = value.strip() + #this raises an ValueError if address is not IpV4 or IpV6 + ipaddr.IPNetwork(address=addr) except ValueError: raise formencode.Invalid(self.message('badFormat', state), value, state) - def to_python(self, value, state): - v = super(_validator, self).to_python(value, state) - #if IP doesn't end with a mask, add /32 - if '/' not in value: - v += '/32' - return v return _validator