# HG changeset patch # User Mads Kiilerich # Date 2018-12-31 02:25:11 # Node ID 93834966ae01cc3e663d22ce9e1812418f0ff02b # Parent 71713cf466b9bb71fc56fab1b8c2368e619b3583 auth: global permissions given to the default user are the bare minimum and should apply to *all* other users too Drop the "subtractive permission" config option "inherit_from_default" that when set to false would give users less global permissions than the default unauthenticated user. Instead, think positive and merge all positive permissions. At the end, filter the global permissions to make sure we for each kind of permissions only keep the one with most weight. diff --git a/kallithea/config/rcextensions/__init__.py b/kallithea/config/rcextensions/__init__.py --- a/kallithea/config/rcextensions/__init__.py +++ b/kallithea/config/rcextensions/__init__.py @@ -105,7 +105,6 @@ def _cruserhook(*args, **kwargs): :param active: :param password: :param emails: - :param inherit_default_permissions: :param created_by: """ return 0 @@ -169,7 +168,6 @@ def _dluserhook(*args, **kwargs): :param active: :param password: :param emails: - :param inherit_default_permissions: :param deleted_by: """ return 0 diff --git a/kallithea/controllers/admin/user_groups.py b/kallithea/controllers/admin/user_groups.py --- a/kallithea/controllers/admin/user_groups.py +++ b/kallithea/controllers/admin/user_groups.py @@ -369,8 +369,6 @@ class UserGroupsController(BaseControlle form = CustomDefaultPermissionsForm()() form_result = form.to_python(request.POST) - inherit_perms = form_result['inherit_default_permissions'] - user_group.inherit_default_permissions = inherit_perms usergroup_model = UserGroupModel() defs = UserGroupToPerm.query() \ diff --git a/kallithea/controllers/admin/users.py b/kallithea/controllers/admin/users.py --- a/kallithea/controllers/admin/users.py +++ b/kallithea/controllers/admin/users.py @@ -315,8 +315,6 @@ class UsersController(BaseController): form = CustomDefaultPermissionsForm()() form_result = form.to_python(request.POST) - inherit_perms = form_result['inherit_default_permissions'] - user.inherit_default_permissions = inherit_perms user_model = UserModel() defs = UserToPerm.query() \ @@ -391,7 +389,6 @@ class UsersController(BaseController): c.user_ip_map = UserIpMap.query() \ .filter(UserIpMap.user == c.user).all() - c.inherit_default_ips = c.user.inherit_default_permissions c.default_user_ip_map = UserIpMap.query() \ .filter(UserIpMap.user == User.get_default_user()).all() diff --git a/kallithea/lib/auth.py b/kallithea/lib/auth.py --- a/kallithea/lib/auth.py +++ b/kallithea/lib/auth.py @@ -132,7 +132,7 @@ def check_password(password, hashed): % __platform__) -def _cached_perms_data(user_id, user_is_admin, user_inherit_default_permissions, +def _cached_perms_data(user_id, user_is_admin, explicit): RK = 'repositories' GK = 'repositories_groups' @@ -226,14 +226,8 @@ def _cached_perms_data(user_id, user_is_ permissions[UK][u_k] = p #====================================================================== - # !! OVERRIDE GLOBALS !! with user permissions if any found + # !! Augment GLOBALS with user permissions if any found !! #====================================================================== - # those can be configured from groups or users explicitly - _configurable = set([ - 'hg.fork.none', 'hg.fork.repository', - 'hg.create.none', 'hg.create.repository', - 'hg.usergroup.create.false', 'hg.usergroup.create.true' - ]) # USER GROUPS comes first # user group global permissions @@ -253,14 +247,6 @@ def _cached_perms_data(user_id, user_is_ itertools.groupby(user_perms_from_users_groups, lambda x:x.users_group)] for gr, perms in _grouped: - # since user can be in multiple groups iterate over them and - # select the lowest permissions first (more explicit) - # TODO: do this^^ - if not gr.inherit_default_permissions: - # NEED TO IGNORE all configurable permissions and - # replace them with explicitly set - permissions[GLOBAL] = permissions[GLOBAL] \ - .difference(_configurable) for perm in perms: permissions[GLOBAL].add(perm.permission.permission_name) @@ -269,14 +255,15 @@ def _cached_perms_data(user_id, user_is_ .options(joinedload(UserToPerm.permission)) \ .filter(UserToPerm.user_id == user_id).all() - if not user_inherit_default_permissions: - # NEED TO IGNORE all configurable permissions and - # replace them with explicitly set - permissions[GLOBAL] = permissions[GLOBAL] \ - .difference(_configurable) + for perm in user_perms: + permissions[GLOBAL].add(perm.permission.permission_name) - for perm in user_perms: - permissions[GLOBAL].add(perm.permission.permission_name) + # for each kind of global permissions, only keep the one with heighest weight + kind_max_perm = {} + for perm in sorted(permissions[GLOBAL], key=lambda n: PERM_WEIGHTS[n]): + kind = perm.rsplit('.', 1)[0] + kind_max_perm[kind] = perm + permissions[GLOBAL] = set(kind_max_perm.values()) ## END GLOBAL PERMISSIONS #====================================================================== @@ -485,7 +472,6 @@ class AuthUser(object): self.lastname = '' self.email = '' self.admin = False - self.inherit_default_permissions = False # Look up database user, if necessary. if user_id is not None: @@ -587,13 +573,11 @@ class AuthUser(object): """ user_id = user.user_id user_is_admin = user.is_admin - user_inherit_default_permissions = user.inherit_default_permissions log.debug('Getting PERMISSION tree') compute = conditional_cache('short_term', 'cache_desc', condition=cache, func=_cached_perms_data) - return compute(user_id, user_is_admin, - user_inherit_default_permissions, explicit) + return compute(user_id, user_is_admin, explicit) def _get_api_keys(self): api_keys = [self.api_key] @@ -637,8 +621,7 @@ class AuthUser(object): Check if the given IP address (a `str`) is allowed for the given user (an `AuthUser` or `db.User`). """ - allowed_ips = AuthUser.get_allowed_ips(user.user_id, cache=True, - inherit_from_default=user.inherit_default_permissions) + allowed_ips = AuthUser.get_allowed_ips(user.user_id, cache=True) 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 @@ -672,30 +655,26 @@ class AuthUser(object): return au @classmethod - def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False): + def get_allowed_ips(cls, user_id, cache=False): _set = set() - if inherit_from_default: - default_ips = UserIpMap.query().filter(UserIpMap.user_id == - User.get_default_user(cache=True).user_id) - if cache: - default_ips = default_ips.options(FromCache("sql_cache_short", - "get_user_ips_default")) - - # populate from default user - for ip in default_ips: - 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 + default_ips = UserIpMap.query().filter(UserIpMap.user_id == + User.get_default_user(cache=True).user_id) + if cache: + default_ips = default_ips.options(FromCache("sql_cache_short", + "get_user_ips_default")) + for ip in default_ips: + 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 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: try: _set.add(ip.ip_addr) diff --git a/kallithea/lib/hooks.py b/kallithea/lib/hooks.py --- a/kallithea/lib/hooks.py +++ b/kallithea/lib/hooks.py @@ -212,7 +212,6 @@ def log_create_user(user_dict, created_b 'active', 'password', 'emails', - 'inherit_default_permissions' """ from kallithea import EXTENSIONS @@ -285,7 +284,6 @@ def log_delete_user(user_dict, deleted_b 'active', 'password', 'emails', - 'inherit_default_permissions' """ from kallithea import EXTENSIONS diff --git a/kallithea/model/db.py b/kallithea/model/db.py --- a/kallithea/model/db.py +++ b/kallithea/model/db.py @@ -426,7 +426,6 @@ class User(Base, BaseDbModel): extern_type = Column(String(255), nullable=True) # FIXME: not nullable? extern_name = Column(String(255), nullable=True) # FIXME: not nullable? api_key = Column(String(255), nullable=False) - inherit_default_permissions = Column(Boolean(), nullable=False, default=True) created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now) _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data # FIXME: not nullable? @@ -820,7 +819,6 @@ class UserGroup(Base, BaseDbModel): users_group_name = Column(Unicode(255), nullable=False, unique=True) user_group_description = Column(Unicode(10000), nullable=True) # FIXME: not nullable? users_group_active = Column(Boolean(), nullable=False) - inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, default=True) owner_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now) _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data # FIXME: not nullable? diff --git a/kallithea/model/forms.py b/kallithea/model/forms.py --- a/kallithea/model/forms.py +++ b/kallithea/model/forms.py @@ -424,7 +424,6 @@ def CustomDefaultPermissionsForm(): class _CustomDefaultPermissionsForm(formencode.Schema): filter_extra_fields = True allow_extra_fields = True - inherit_default_permissions = v.StringBoolean(if_missing=False) create_repo_perm = v.StringBoolean(if_missing=False) create_user_group_perm = v.StringBoolean(if_missing=False) diff --git a/kallithea/templates/admin/users/user_edit_ips.html b/kallithea/templates/admin/users/user_edit_ips.html --- a/kallithea/templates/admin/users/user_edit_ips.html +++ b/kallithea/templates/admin/users/user_edit_ips.html @@ -1,5 +1,5 @@ - %if c.default_user_ip_map and c.inherit_default_ips: + %if c.default_user_ip_map: %for ip in c.default_user_ip_map: diff --git a/kallithea/templates/base/default_perms_box.html b/kallithea/templates/base/default_perms_box.html --- a/kallithea/templates/base/default_perms_box.html +++ b/kallithea/templates/base/default_perms_box.html @@ -8,18 +8,6 @@ ${h.form(form_url)}
- -
- ${h.checkbox('inherit_default_permissions',value=True)} - - ${(h.HTML(_('Select to inherit global settings, IP whitelist and permissions from the %s.')) - % h.link_to(_('default permissions'), url('admin_permissions')))} - -
-
- -
-
${h.checkbox('create_repo_perm',value=True)} @@ -49,8 +37,6 @@ ${h.form(form_url)}
-
-
${h.submit('save',_('Save'),class_="btn btn-default")} @@ -59,23 +45,4 @@ ${h.form(form_url)}
${h.end_form()} - -## JS - - diff --git a/kallithea/tests/functional/test_forks.py b/kallithea/tests/functional/test_forks.py --- a/kallithea/tests/functional/test_forks.py +++ b/kallithea/tests/functional/test_forks.py @@ -7,7 +7,7 @@ from kallithea.tests.base import * from kallithea.tests.fixture import Fixture from kallithea.lib.utils2 import safe_str, safe_unicode -from kallithea.model.db import Repository +from kallithea.model.db import Repository, User from kallithea.model.repo import RepoModel from kallithea.model.user import UserModel from kallithea.model.meta import Session @@ -44,20 +44,19 @@ class _BaseTestCase(TestController): response.mustcontain("""There are no forks yet""") def test_no_permissions_to_fork(self): - usr = self.log_user(TEST_USER_REGULAR_LOGIN, - TEST_USER_REGULAR_PASS)['user_id'] + self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)['user_id'] try: user_model = UserModel() + usr = User.get_default_user() user_model.revoke_perm(usr, 'hg.fork.repository') user_model.grant_perm(usr, 'hg.fork.none') - u = UserModel().get(usr) - u.inherit_default_permissions = False Session().commit() # try create a fork repo_name = self.REPO self.app.post(url(controller='forks', action='fork_create', repo_name=repo_name), {'_authentication_token': self.authentication_token()}, status=403) finally: + usr = User.get_default_user() user_model.revoke_perm(usr, 'hg.fork.none') user_model.grant_perm(usr, 'hg.fork.repository') Session().commit() diff --git a/kallithea/tests/models/test_permissions.py b/kallithea/tests/models/test_permissions.py --- a/kallithea/tests/models/test_permissions.py +++ b/kallithea/tests/models/test_permissions.py @@ -310,7 +310,7 @@ class TestPermissions(TestController): u1_auth = AuthUser(user_id=self.u1.user_id) assert u1_auth.permissions['repositories_groups'] == {u'group1': u'group.read'} - def test_inherited_permissions_from_default_on_user_enabled(self): + def test_inherit_nice_permissions_from_default_user(self): user_model = UserModel() # enable fork and create on default user usr = 'default' @@ -318,8 +318,6 @@ class TestPermissions(TestController): user_model.grant_perm(usr, 'hg.create.repository') user_model.revoke_perm(usr, 'hg.fork.none') user_model.grant_perm(usr, 'hg.fork.repository') - # make sure inherit flag is turned on - self.u1.inherit_default_permissions = True Session().commit() u1_auth = AuthUser(user_id=self.u1.user_id) # this user will have inherited permissions from default user @@ -329,7 +327,7 @@ class TestPermissions(TestController): 'repository.read', 'group.read', 'usergroup.read', 'hg.create.write_on_repogroup.true']) - def test_inherited_permissions_from_default_on_user_disabled(self): + def test_inherit_sad_permissions_from_default_user(self): user_model = UserModel() # disable fork and create on default user usr = 'default' @@ -337,8 +335,6 @@ class TestPermissions(TestController): user_model.grant_perm(usr, 'hg.create.none') user_model.revoke_perm(usr, 'hg.fork.repository') user_model.grant_perm(usr, 'hg.fork.none') - # make sure inherit flag is turned on - self.u1.inherit_default_permissions = True Session().commit() u1_auth = AuthUser(user_id=self.u1.user_id) # this user will have inherited permissions from default user @@ -348,7 +344,7 @@ class TestPermissions(TestController): 'repository.read', 'group.read', 'usergroup.read', 'hg.create.write_on_repogroup.true']) - def test_non_inherited_permissions_from_default_on_user_enabled(self): + def test_inherit_more_permissions_from_default_user(self): user_model = UserModel() # enable fork and create on default user usr = 'default' @@ -363,19 +359,18 @@ class TestPermissions(TestController): user_model.revoke_perm(self.u1, 'hg.fork.repository') user_model.grant_perm(self.u1, 'hg.fork.none') - # make sure inherit flag is turned off - self.u1.inherit_default_permissions = False Session().commit() u1_auth = AuthUser(user_id=self.u1.user_id) - # this user will have non inherited permissions from he's - # explicitly set permissions - assert u1_auth.permissions['global'] == set(['hg.create.none', 'hg.fork.none', + # this user will have inherited more permissions from default user + assert u1_auth.permissions['global'] == set([ + 'hg.create.repository', + 'hg.fork.repository', 'hg.register.manual_activate', 'hg.extern_activate.auto', 'repository.read', 'group.read', 'usergroup.read', 'hg.create.write_on_repogroup.true']) - def test_non_inherited_permissions_from_default_on_user_disabled(self): + def test_inherit_less_permissions_from_default_user(self): user_model = UserModel() # disable fork and create on default user usr = 'default' @@ -390,25 +385,21 @@ class TestPermissions(TestController): user_model.revoke_perm(self.u1, 'hg.fork.none') user_model.grant_perm(self.u1, 'hg.fork.repository') - # make sure inherit flag is turned off - self.u1.inherit_default_permissions = False Session().commit() u1_auth = AuthUser(user_id=self.u1.user_id) - # this user will have non inherited permissions from he's - # explicitly set permissions - assert u1_auth.permissions['global'] == set(['hg.create.repository', 'hg.fork.repository', + # this user will have inherited less permissions from default user + assert u1_auth.permissions['global'] == set([ + 'hg.create.repository', + 'hg.fork.repository', 'hg.register.manual_activate', 'hg.extern_activate.auto', 'repository.read', 'group.read', 'usergroup.read', 'hg.create.write_on_repogroup.true']) def test_inactive_user_group_does_not_affect_global_permissions(self): - # Issue #138: Inactive User Groups affecting permissions # Add user to inactive user group, set specific permissions on user - # group and disable inherit-from-default. User permissions should still - # inherit from default. + # group and and verify it really is inactive. self.ug1 = fixture.create_user_group(u'G1') - self.ug1.inherit_default_permissions = False user_group_model = UserGroupModel() user_group_model.add_user_to_group(self.ug1, self.u1) user_group_model.update(self.ug1, {'users_group_active': False}) @@ -438,12 +429,9 @@ class TestPermissions(TestController): 'hg.create.write_on_repogroup.true']) def test_inactive_user_group_does_not_affect_global_permissions_inverse(self): - # Issue #138: Inactive User Groups affecting permissions # Add user to inactive user group, set specific permissions on user - # group and disable inherit-from-default. User permissions should still - # inherit from default. + # group and and verify it really is inactive. self.ug1 = fixture.create_user_group(u'G1') - self.ug1.inherit_default_permissions = False user_group_model = UserGroupModel() user_group_model.add_user_to_group(self.ug1, self.u1) user_group_model.update(self.ug1, {'users_group_active': False}) @@ -474,7 +462,6 @@ class TestPermissions(TestController): def test_inactive_user_group_does_not_affect_repo_permissions(self): self.ug1 = fixture.create_user_group(u'G1') - self.ug1.inherit_default_permissions = False user_group_model = UserGroupModel() user_group_model.add_user_to_group(self.ug1, self.u1) user_group_model.update(self.ug1, {'users_group_active': False}) @@ -499,7 +486,6 @@ class TestPermissions(TestController): def test_inactive_user_group_does_not_affect_repo_permissions_inverse(self): self.ug1 = fixture.create_user_group(u'G1') - self.ug1.inherit_default_permissions = False user_group_model = UserGroupModel() user_group_model.add_user_to_group(self.ug1, self.u1) user_group_model.update(self.ug1, {'users_group_active': False}) @@ -524,7 +510,6 @@ class TestPermissions(TestController): def test_inactive_user_group_does_not_affect_repo_group_permissions(self): self.ug1 = fixture.create_user_group(u'G1') - self.ug1.inherit_default_permissions = False user_group_model = UserGroupModel() user_group_model.add_user_to_group(self.ug1, self.u1) user_group_model.update(self.ug1, {'users_group_active': False}) @@ -545,7 +530,6 @@ class TestPermissions(TestController): def test_inactive_user_group_does_not_affect_repo_group_permissions_inverse(self): self.ug1 = fixture.create_user_group(u'G1') - self.ug1.inherit_default_permissions = False user_group_model = UserGroupModel() user_group_model.add_user_to_group(self.ug1, self.u1) user_group_model.update(self.ug1, {'users_group_active': False}) @@ -566,7 +550,6 @@ class TestPermissions(TestController): def test_inactive_user_group_does_not_affect_user_group_permissions(self): self.ug1 = fixture.create_user_group(u'G1') - self.ug1.inherit_default_permissions = False user_group_model = UserGroupModel() user_group_model.add_user_to_group(self.ug1, self.u1) user_group_model.update(self.ug1, {'users_group_active': False}) @@ -588,7 +571,6 @@ class TestPermissions(TestController): def test_inactive_user_group_does_not_affect_user_group_permissions_inverse(self): self.ug1 = fixture.create_user_group(u'G1') - self.ug1.inherit_default_permissions = False user_group_model = UserGroupModel() user_group_model.add_user_to_group(self.ug1, self.u1) user_group_model.update(self.ug1, {'users_group_active': False})
${ip.ip_addr}