]> source.dussan.org Git - gitblit.git/commitdiff
Enforce strict order for permission determination
authorJames Moger <james.moger@gitblit.com>
Tue, 23 Oct 2012 21:35:42 +0000 (17:35 -0400)
committerJames Moger <james.moger@gitblit.com>
Tue, 23 Oct 2012 21:35:42 +0000 (17:35 -0400)
The order of permissions defined within a user or team is preserved
during read and write.  This order is important for determining the
regex match used within the user or team object.

If the user is an admin or repository owner, then RW+
Else if user has an explicit permission, use that
Else check for the first regex match in user permissions
Else check for the HIGHEST permission from team memberships

If the team is an admin team, then RW+
Else if a team has an explicit permission, use that
Else check for the first regex match in team permissions

src/com/gitblit/models/TeamModel.java
src/com/gitblit/models/UserModel.java
tests/com/gitblit/tests/PermissionsTest.java

index 6410eb45f45b8077a828a425db3a43d1231d3361..7d557db97851e9860acaacf77f2679d29c617794 100644 (file)
@@ -19,8 +19,8 @@ import java.io.Serializable;
 import java.util.ArrayList;\r
 import java.util.Collection;\r
 import java.util.Collections;\r
-import java.util.HashMap;\r
 import java.util.HashSet;\r
+import java.util.LinkedHashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Set;\r
@@ -51,7 +51,7 @@ public class TeamModel implements Serializable, Comparable<TeamModel> {
        // retained for backwards-compatibility with RPC clients\r
        @Deprecated\r
        public final Set<String> repositories = new HashSet<String>();\r
-       public final Map<String, AccessPermission> permissions = new HashMap<String, AccessPermission>();\r
+       public final Map<String, AccessPermission> permissions = new LinkedHashMap<String, AccessPermission>();\r
        public final Set<String> mailingLists = new HashSet<String>();\r
        public final List<String> preReceiveScripts = new ArrayList<String>();\r
        public final List<String> postReceiveScripts = new ArrayList<String>();\r
@@ -191,6 +191,8 @@ public class TeamModel implements Serializable, Comparable<TeamModel> {
                                        AccessPermission p = permissions.get(key);\r
                                        if (p != null) {\r
                                                permission = p;\r
+                                               // take first match\r
+                                               break;\r
                                        }\r
                                }\r
                        }\r
@@ -198,7 +200,7 @@ public class TeamModel implements Serializable, Comparable<TeamModel> {
                return permission;\r
        }\r
        \r
-       private boolean canAccess(RepositoryModel repository, AccessRestrictionType ifRestriction, AccessPermission requirePermission) {\r
+       protected boolean canAccess(RepositoryModel repository, AccessRestrictionType ifRestriction, AccessPermission requirePermission) {\r
                if (repository.accessRestriction.atLeast(ifRestriction)) {\r
                        AccessPermission permission = getRepositoryPermission(repository);\r
                        return permission.atLeast(requirePermission);\r
index 6cc077895d7d49ccac5c0b2078ed172724c34edb..d7bc29351f9a384ba5f9e8ccf9748facfdcbb1d8 100644 (file)
@@ -19,8 +19,8 @@ import java.io.Serializable;
 import java.security.Principal;\r
 import java.util.ArrayList;\r
 import java.util.Collections;\r
-import java.util.HashMap;\r
 import java.util.HashSet;\r
+import java.util.LinkedHashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Set;\r
@@ -60,7 +60,7 @@ public class UserModel implements Principal, Serializable, Comparable<UserModel>
        // retained for backwards-compatibility with RPC clients\r
        @Deprecated\r
        public final Set<String> repositories = new HashSet<String>();\r
-       public final Map<String, AccessPermission> permissions = new HashMap<String, AccessPermission>();\r
+       public final Map<String, AccessPermission> permissions = new LinkedHashMap<String, AccessPermission>();\r
        public final Set<TeamModel> teams = new HashSet<TeamModel>();\r
 \r
        // non-persisted fields\r
@@ -217,8 +217,8 @@ public class UserModel implements Principal, Serializable, Comparable<UserModel>
                        return AccessPermission.REWIND;\r
                }\r
                \r
-               // determine best permission available based on user's personal permissions\r
-               // and the permissions of teams of which the user belongs\r
+               // explicit user permission OR user regex match is used\r
+               // if that fails, then the best team permission is used\r
                AccessPermission permission = AccessPermission.NONE;\r
                if (permissions.containsKey(repository.name.toLowerCase())) {\r
                        // exact repository permission specified, use it\r
@@ -232,17 +232,21 @@ public class UserModel implements Principal, Serializable, Comparable<UserModel>
                                if (StringUtils.matchesIgnoreCase(repository.name, key)) {\r
                                        AccessPermission p = permissions.get(key);\r
                                        if (p != null) {\r
+                                               // take first match\r
                                                permission = p;\r
+                                               break;\r
                                        }\r
                                }\r
                        }\r
                }\r
                \r
-               for (TeamModel team : teams) {\r
-                       AccessPermission p = team.getRepositoryPermission(repository);\r
-                       if (permission == null || p.exceeds(permission)) {\r
-                               // use team permission\r
-                               permission = p;\r
+               if (AccessPermission.NONE.equals(permission)) {\r
+                       for (TeamModel team : teams) {\r
+                               AccessPermission p = team.getRepositoryPermission(repository);\r
+                               if (p.exceeds(permission)) {\r
+                                       // use highest team permission\r
+                                       permission = p;\r
+                               }\r
                        }\r
                }\r
                return permission;\r
index c0e406d49d13d577bc50c3d35df000099b00fc47..befd36036d3bdc2bf3798267ee58e8b9a0a867fd 100644 (file)
@@ -2393,7 +2393,7 @@ public class PermissionsTest extends Assert {
        }
        
        @Test
-       public void testWildcardMatching() throws Exception {
+       public void testRegexMatching() throws Exception {
                RepositoryModel repository = new RepositoryModel("ubercool/_my-r/e~po.git", null, null, new Date());
                repository.authorizationControl = AuthorizationControl.NAMED;
                repository.accessRestriction = AccessRestrictionType.VIEW;
@@ -2415,7 +2415,125 @@ public class PermissionsTest extends Assert {
                assertFalse("user CAN delete!", user.canDelete(repository));
                assertFalse("user CAN edit!", user.canEdit(repository));
        }
+
+       @Test
+       public void testRegexIncludeCommonExcludePersonal() throws Exception {
+               
+               UserModel user = new UserModel("test");
+               user.setRepositoryPermission("[^~].*", AccessPermission.CLONE);
+
+               // common
+               RepositoryModel common = new RepositoryModel("ubercool/_my-r/e~po.git", null, null, new Date());
+               common.authorizationControl = AuthorizationControl.NAMED;
+               common.accessRestriction = AccessRestrictionType.VIEW;
+               
+               assertTrue("user DOES NOT HAVE a repository permission!", user.hasRepositoryPermission(common.name));
+               assertTrue("user CAN NOT view!", user.canView(common));
+               assertTrue("user CAN NOT clone!", user.canClone(common));
+               assertFalse("user CAN push!", user.canPush(common));
+               
+               assertFalse("user CAN create ref!", user.canCreateRef(common));
+               assertFalse("user CAN delete ref!", user.canDeleteRef(common));
+               assertFalse("user CAN rewind ref!", user.canRewindRef(common));
+
+               assertFalse("user CAN fork!", user.canFork(common));
+               
+               assertFalse("user CAN delete!", user.canDelete(common));
+               assertFalse("user CAN edit!", user.canEdit(common));
+
+               // personal
+               RepositoryModel personal = new RepositoryModel("~ubercool/_my-r/e~po.git", null, null, new Date());
+               personal.authorizationControl = AuthorizationControl.NAMED;
+               personal.accessRestriction = AccessRestrictionType.VIEW;
+               
+               assertFalse("user HAS a repository permission!", user.hasRepositoryPermission(personal.name));
+               assertFalse("user CAN NOT view!", user.canView(personal));
+               assertFalse("user CAN NOT clone!", user.canClone(personal));
+               assertFalse("user CAN push!", user.canPush(personal));
+               
+               assertFalse("user CAN create ref!", user.canCreateRef(personal));
+               assertFalse("user CAN delete ref!", user.canDeleteRef(personal));
+               assertFalse("user CAN rewind ref!", user.canRewindRef(personal));
+
+               assertFalse("user CAN fork!", user.canFork(personal));
+               
+               assertFalse("user CAN delete!", user.canDelete(personal));
+               assertFalse("user CAN edit!", user.canEdit(personal));
+       }
        
+       @Test
+       public void testRegexMatching2() throws Exception {
+               RepositoryModel personal = new RepositoryModel("~ubercool/_my-r/e~po.git", null, null, new Date());
+               personal.authorizationControl = AuthorizationControl.NAMED;
+               personal.accessRestriction = AccessRestrictionType.VIEW;
+
+               UserModel user = new UserModel("test");
+               // permit all repositories excluding all personal rpeositories
+               user.setRepositoryPermission("[^~].*", AccessPermission.CLONE);
+               // permitall  ~ubercool repositories
+               user.setRepositoryPermission("~ubercool/.*", AccessPermission.CLONE);
+               
+               // personal
+               assertTrue("user DOES NOT HAVE a repository permission!", user.hasRepositoryPermission(personal.name));
+               assertTrue("user CAN NOT view!", user.canView(personal));
+               assertTrue("user CAN NOT clone!", user.canClone(personal));
+               assertFalse("user CAN push!", user.canPush(personal));
+               
+               assertFalse("user CAN create ref!", user.canCreateRef(personal));
+               assertFalse("user CAN delete ref!", user.canDeleteRef(personal));
+               assertFalse("user CAN rewind ref!", user.canRewindRef(personal));
+
+               assertFalse("user CAN fork!", user.canFork(personal));
+               
+               assertFalse("user CAN delete!", user.canDelete(personal));
+               assertFalse("user CAN edit!", user.canEdit(personal));
+       }
+       
+       @Test
+       public void testRegexOrder() throws Exception {
+               RepositoryModel personal = new RepositoryModel("~ubercool/_my-r/e~po.git", null, null, new Date());
+               personal.authorizationControl = AuthorizationControl.NAMED;
+               personal.accessRestriction = AccessRestrictionType.VIEW;
+
+               UserModel user = new UserModel("test");
+               user.setRepositoryPermission(".*", AccessPermission.PUSH);
+               user.setRepositoryPermission("~ubercool/.*", AccessPermission.CLONE);
+               
+               // has PUSH access because first match is PUSH permission 
+               assertTrue("user HAS a repository permission!", user.hasRepositoryPermission(personal.name));
+               assertTrue("user CAN NOT view!", user.canView(personal));
+               assertTrue("user CAN NOT clone!", user.canClone(personal));
+               assertTrue("user CAN NOT push!", user.canPush(personal));
+               
+               assertFalse("user CAN create ref!", user.canCreateRef(personal));
+               assertFalse("user CAN delete ref!", user.canDeleteRef(personal));
+               assertFalse("user CAN rewind ref!", user.canRewindRef(personal));
+
+               assertFalse("user CAN fork!", user.canFork(personal));
+               
+               assertFalse("user CAN delete!", user.canDelete(personal));
+               assertFalse("user CAN edit!", user.canEdit(personal));
+                               
+               user.permissions.clear();
+               user.setRepositoryPermission("~ubercool/.*", AccessPermission.CLONE);
+               user.setRepositoryPermission(".*", AccessPermission.PUSH);
+               
+               // has CLONE access because first match is CLONE permission
+               assertTrue("user HAS a repository permission!", user.hasRepositoryPermission(personal.name));
+               assertTrue("user CAN NOT view!", user.canView(personal));
+               assertTrue("user CAN NOT clone!", user.canClone(personal));
+               assertFalse("user CAN push!", user.canPush(personal));
+                               
+               assertFalse("user CAN create ref!", user.canCreateRef(personal));
+               assertFalse("user CAN delete ref!", user.canDeleteRef(personal));
+               assertFalse("user CAN rewind ref!", user.canRewindRef(personal));
+
+               assertFalse("user CAN fork!", user.canFork(personal));
+                               
+               assertFalse("user CAN delete!", user.canDelete(personal));
+               assertFalse("user CAN edit!", user.canEdit(personal));
+       }
+
        @Test
        public void testAdminTeamInheritance() throws Exception {
                UserModel user = new UserModel("test");