aboutsummaryrefslogtreecommitdiff
path: root/rhodecode/model
diff options
context:
space:
mode:
authorMarcin Kuzminski <marcin@python-works.com>2012-12-30 23:06:03 +0100
committerMarcin Kuzminski <marcin@python-works.com>2012-12-30 23:06:03 +0100
commitb8e1df75b21aad11a161aa3930eb7f26c1c45770 (patch)
treefcc9b54514288e334d5cf135ecb0e28fb12053bb /rhodecode/model
parent41981be79eefe651870aab3138d143296a4205a2 (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-xrhodecode/model/db.py28
-rw-r--r--rhodecode/model/forms.py9
-rw-r--r--rhodecode/model/user.py32
-rw-r--r--rhodecode/model/validators.py41
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