diff options
author | Marcin Kuzminski <marcin@python-works.com> | 2012-12-30 23:06:03 +0100 |
---|---|---|
committer | Marcin Kuzminski <marcin@python-works.com> | 2012-12-30 23:06:03 +0100 |
commit | b8e1df75b21aad11a161aa3930eb7f26c1c45770 (patch) | |
tree | fcc9b54514288e334d5cf135ecb0e28fb12053bb /rhodecode/model | |
parent | 41981be79eefe651870aab3138d143296a4205a2 (diff) |
Added UserIpMap interface for allowed IP addresses and IP restriction access
ref #264 IP restriction for users and user groups
--HG--
branch : beta
extra : amend_source : b1cad1d9ff6ef50b570689dacec7902a8909895b
Diffstat (limited to 'rhodecode/model')
-rwxr-xr-x | rhodecode/model/db.py | 28 | ||||
-rw-r--r-- | rhodecode/model/forms.py | 9 | ||||
-rw-r--r-- | rhodecode/model/user.py | 32 | ||||
-rw-r--r-- | rhodecode/model/validators.py | 41 |
4 files changed, 105 insertions, 5 deletions
diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py index 1d5ab5ba..6030b468 100755 --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -518,6 +518,33 @@ class UserEmailMap(Base, BaseModel): self._email = val.lower() if val else None +class UserIpMap(Base, BaseModel): + __tablename__ = 'user_ip_map' + __table_args__ = ( + UniqueConstraint('user_id', 'ip_addr'), + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8'} + ) + __mapper_args__ = {} + + 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) + user = relationship('User', lazy='joined') + + @classmethod + def _get_ip_range(cls, ip_addr): + from rhodecode.lib import ipaddr + net = ipaddr.IPv4Network(ip_addr) + return [str(net.network), str(net.broadcast)] + + def __json__(self): + return dict( + ip_addr=self.ip_addr, + ip_range=self._get_ip_range(self.ip_addr) + ) + + class UserLog(Base, BaseModel): __tablename__ = 'user_logs' __table_args__ = ( @@ -637,6 +664,7 @@ class Repository(Base, BaseModel): landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None) enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None) + #changeset_cache = Column("changeset_cache", LargeBinary(), nullable=False) #JSON data fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py index b46e6274..851640d8 100644 --- a/rhodecode/model/forms.py +++ b/rhodecode/model/forms.py @@ -345,11 +345,16 @@ def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, def UserExtraEmailForm(): class _UserExtraEmailForm(formencode.Schema): - email = All(v.UniqSystemEmail(), v.Email) - + email = All(v.UniqSystemEmail(), v.Email(not_empty=True)) return _UserExtraEmailForm +def UserExtraIpForm(): + class _UserExtraIpForm(formencode.Schema): + ip = v.ValidIp()(not_empty=True) + return _UserExtraIpForm + + def PullRequestForm(repo_id): class _PullRequestForm(formencode.Schema): allow_extra_fields = True diff --git a/rhodecode/model/user.py b/rhodecode/model/user.py index 89657793..51cc28e4 100644 --- a/rhodecode/model/user.py +++ b/rhodecode/model/user.py @@ -40,7 +40,7 @@ from rhodecode.model import BaseModel from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \ UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \ Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \ - UserEmailMap + UserEmailMap, UserIpMap from rhodecode.lib.exceptions import DefaultUserException, \ UserOwnsReposException @@ -705,3 +705,33 @@ class UserModel(BaseModel): obj = UserEmailMap.query().get(email_id) if obj: self.sa.delete(obj) + + def add_extra_ip(self, user, ip): + """ + Adds ip address to UserIpMap + + :param user: + :param ip: + """ + from rhodecode.model import forms + form = forms.UserExtraIpForm()() + data = form.to_python(dict(ip=ip)) + user = self._get_user(user) + + obj = UserIpMap() + obj.user = user + obj.ip_addr = data['ip'] + self.sa.add(obj) + return obj + + def delete_extra_ip(self, user, ip_id): + """ + Removes ip address from UserIpMap + + :param user: + :param ip_id: + """ + user = self._get_user(user) + obj = UserIpMap.query().get(ip_id) + if obj: + self.sa.delete(obj) diff --git a/rhodecode/model/validators.py b/rhodecode/model/validators.py index 9923f28e..a9fe81fe 100644 --- a/rhodecode/model/validators.py +++ b/rhodecode/model/validators.py @@ -11,7 +11,7 @@ from webhelpers.pylonslib.secure_form import authentication_token from formencode.validators import ( UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, - NotEmpty + NotEmpty, IPAddress, CIDR ) from rhodecode.lib.compat import OrderedSet from rhodecode.lib.utils import repo_name_slug @@ -23,7 +23,7 @@ from rhodecode.lib.auth import HasReposGroupPermissionAny # silence warnings and pylint UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \ - NotEmpty + NotEmpty, IPAddress, CIDR log = logging.getLogger(__name__) @@ -706,3 +706,40 @@ def NotReviewedRevisions(repo_id): ) return _validator + + +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)'), + illegalBits=_('The network size (bits) must be within the range' + ' of 0-32 (not %(bits)r)')) + + 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 + 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 |