src/com/gitblit/AccessRestrictionFilter.java
@@ -156,7 +156,7 @@ return; } else { // check user access for request if (user.canAdmin || canAccess(model, user, urlRequestType)) { if (user.canAdmin() || canAccess(model, user, urlRequestType)) { // authenticated request permitted. // pass processing to the restricted servlet. newSession(authenticatedRequest, httpResponse); src/com/gitblit/AuthenticationFilter.java
@@ -189,7 +189,7 @@ @Override public boolean isUserInRole(String role) { if (role.equals(Constants.ADMIN_ROLE)) { return user.canAdmin; return user.canAdmin(); } // Gitblit does not currently use actual roles in the traditional // servlet container sense. That is the reason this is marked src/com/gitblit/ConfigUserService.java
@@ -862,6 +862,24 @@ // write teams for (TeamModel model : teams.values()) { // team roles List<String> roles = new ArrayList<String>(); if (model.canAdmin) { roles.add(Constants.ADMIN_ROLE); } if (model.canFork) { roles.add(Constants.FORK_ROLE); } if (model.canCreate) { roles.add(Constants.CREATE_ROLE); } if (roles.size() == 0) { // we do this to ensure that team record is written. // Otherwise, StoredConfig might optimizes that record away. roles.add(Constants.NO_ROLE); } config.setStringList(TEAM, model.name, ROLE, roles); if (model.permissions == null) { // null check on "final" repositories because JSON-sourced TeamModel // can have a null repositories object @@ -982,6 +1000,12 @@ Set<String> teamnames = config.getSubsections(TEAM); for (String teamname : teamnames) { TeamModel team = new TeamModel(teamname); Set<String> roles = new HashSet<String>(Arrays.asList(config.getStringList( TEAM, teamname, ROLE))); team.canAdmin = roles.contains(Constants.ADMIN_ROLE); team.canFork = roles.contains(Constants.FORK_ROLE); team.canCreate = roles.contains(Constants.CREATE_ROLE); team.addRepositoryPermissions(Arrays.asList(config.getStringList(TEAM, teamname, REPOSITORY))); team.addUsers(Arrays.asList(config.getStringList(TEAM, teamname, USER))); src/com/gitblit/FileUserService.java
@@ -780,6 +780,20 @@ } else if (role.charAt(0) == '%') { postReceive.add(role.substring(1)); } else { switch (role.charAt(0)) { case '#': // Permissions if (role.equalsIgnoreCase(Constants.ADMIN_ROLE)) { team.canAdmin = true; } else if (role.equalsIgnoreCase(Constants.FORK_ROLE)) { team.canFork = true; } else if (role.equalsIgnoreCase(Constants.CREATE_ROLE)) { team.canCreate = true; } break; default: repositories.add(role); } repositories.add(role); } } @@ -1040,6 +1054,17 @@ } } // Permissions if (model.canAdmin) { roles.add(Constants.ADMIN_ROLE); } if (model.canFork) { roles.add(Constants.FORK_ROLE); } if (model.canCreate) { roles.add(Constants.CREATE_ROLE); } for (String role : roles) { sb.append(role); sb.append(','); src/com/gitblit/RpcFilter.java
@@ -105,7 +105,7 @@ return; } else { // check user access for request if (user.canAdmin || canAccess(user, requestType)) { if (user.canAdmin() || canAccess(user, requestType)) { // authenticated request permitted. // pass processing to the restricted servlet. newSession(authenticatedRequest, httpResponse); @@ -140,7 +140,7 @@ case LIST_REPOSITORIES: return true; default: return user.canAdmin; return user.canAdmin(); } } } src/com/gitblit/RpcServlet.java
@@ -73,10 +73,10 @@ UserModel user = (UserModel) request.getUserPrincipal(); boolean allowManagement = user != null && user.canAdmin boolean allowManagement = user != null && user.canAdmin() && GitBlit.getBoolean(Keys.web.enableRpcManagement, false); boolean allowAdmin = user != null && user.canAdmin boolean allowAdmin = user != null && user.canAdmin() && GitBlit.getBoolean(Keys.web.enableRpcAdministration, false); Object result = null; src/com/gitblit/client/UsersTableModel.java
@@ -102,7 +102,7 @@ case Display_Name: return model.displayName; case AccessLevel: if (model.canAdmin) { if (model.canAdmin()) { return "administrator"; } return ""; src/com/gitblit/models/TeamModel.java
@@ -41,6 +41,9 @@ // field names are reflectively mapped in EditTeam page public String name; public boolean canAdmin; public boolean canFork; public boolean canCreate; public final Set<String> users = new HashSet<String>(); // retained for backwards-compatibility with RPC clients @Deprecated src/com/gitblit/models/UserModel.java
@@ -26,6 +26,7 @@ import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.Unused; import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.StringUtils; /** @@ -80,7 +81,7 @@ */ @Deprecated public boolean canAccessRepository(String repositoryName) { return canAdmin || repositories.contains(repositoryName.toLowerCase()) return canAdmin() || repositories.contains(repositoryName.toLowerCase()) || hasTeamAccess(repositoryName); } @@ -90,7 +91,7 @@ boolean isOwner = !StringUtils.isEmpty(repository.owner) && repository.owner.equals(username); boolean allowAuthenticated = isAuthenticated && AuthorizationControl.AUTHENTICATED.equals(repository.authorizationControl); return canAdmin || isOwner || repositories.contains(repository.name.toLowerCase()) return canAdmin() || isOwner || repositories.contains(repository.name.toLowerCase()) || hasTeamAccess(repository.name) || allowAuthenticated; } @@ -177,7 +178,7 @@ } public AccessPermission getRepositoryPermission(RepositoryModel repository) { if (canAdmin || repository.isOwner(username) || repository.isUsersPersonalRepository(username)) { if (canAdmin() || repository.isOwner(username) || repository.isUsersPersonalRepository(username)) { return AccessPermission.REWIND; } if (AuthorizationControl.AUTHENTICATED.equals(repository.authorizationControl) && isAuthenticated) { @@ -265,24 +266,84 @@ // can not fork your own repository return false; } if (canAdmin || repository.isOwner(username)) { if (canAdmin() || repository.isOwner(username)) { return true; } if (!repository.allowForks) { return false; } if (!isAuthenticated || !canFork) { if (!isAuthenticated || !canFork()) { return false; } return canClone(repository); } public boolean canDelete(RepositoryModel model) { return canAdmin || model.isUsersPersonalRepository(username); return canAdmin() || model.isUsersPersonalRepository(username); } public boolean canEdit(RepositoryModel model) { return canAdmin || model.isUsersPersonalRepository(username) || model.isOwner(username); return canAdmin() || model.isUsersPersonalRepository(username) || model.isOwner(username); } /** * This returns true if the user has fork privileges or the user has fork * privileges because of a team membership. * * @return true if the user can fork */ public boolean canFork() { if (canFork) { return true; } if (!ArrayUtils.isEmpty(teams)) { for (TeamModel team : teams) { if (team.canFork) { return true; } } } return false; } /** * This returns true if the user has admin privileges or the user has admin * privileges because of a team membership. * * @return true if the user can admin */ public boolean canAdmin() { if (canAdmin) { return true; } if (!ArrayUtils.isEmpty(teams)) { for (TeamModel team : teams) { if (team.canAdmin) { return true; } } } return false; } /** * This returns true if the user has create privileges or the user has create * privileges because of a team membership. * * @return true if the user can admin */ public boolean canCreate() { if (canCreate) { return true; } if (!ArrayUtils.isEmpty(teams)) { for (TeamModel team : teams) { if (team.canCreate) { return true; } } } return false; } public boolean isTeamMember(String teamname) { src/com/gitblit/wicket/AuthorizationStrategy.java
@@ -60,7 +60,7 @@ if (authenticateAdmin) { // authenticate admin if (user != null) { return user.canAdmin; return user.canAdmin(); } return false; } else { src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -329,7 +329,7 @@ gb.allowForksDescription = allow authorized users to fork this repository gb.forkedFrom = forked from gb.canFork = can fork gb.canForkDescription = user is permitted to fork authorized repositories gb.canForkDescription = can fork authorized repositories to a personal repository gb.myFork = view my fork gb.forksProhibited = forks prohibited gb.forksProhibitedWarning = this repository forbids forks src/com/gitblit/wicket/GitBlitWebSession.java
@@ -103,7 +103,7 @@ if (user == null) { return false; } return user.canAdmin; return user.canAdmin(); } public String getUsername() { src/com/gitblit/wicket/pages/EditRepositoryPage.java
@@ -83,7 +83,7 @@ GitBlitWebSession session = GitBlitWebSession.get(); UserModel user = session.getUser(); if (user != null && user.canCreate && !user.canAdmin) { if (user != null && user.canCreate() && !user.canAdmin()) { // personal create permissions, inject personal repository path model.name = user.getPersonalPath() + "/"; model.projectPath = user.getPersonalPath(); @@ -120,7 +120,7 @@ final UserModel user = session.getUser() == null ? UserModel.ANONYMOUS : session.getUser(); if (isCreate) { if (user.canAdmin) { if (user.canAdmin()) { super.setupPage(getString("gb.newRepository"), ""); } else { super.setupPage(getString("gb.newRepository"), user.getDisplayName()); @@ -253,7 +253,7 @@ return; } if (user.canCreate && !user.canAdmin) { if (user.canCreate() && !user.canAdmin()) { // ensure repository name begins with the user's path if (!repositoryModel.name.startsWith(user.getPersonalPath())) { error(MessageFormat.format(getString("gb.illegalPersonalRepositoryLocation"), @@ -474,13 +474,13 @@ } if (isCreate) { // Create Repository if (!user.canCreate && !user.canAdmin) { if (!user.canCreate() && !user.canAdmin()) { // Only administrators or permitted users may create error(getString("gb.errorOnlyAdminMayCreateRepository"), true); } } else { // Edit Repository if (user.canAdmin) { if (user.canAdmin()) { // Admins can edit everything isAdmin = true; return; src/com/gitblit/wicket/pages/EditTeamPage.html
@@ -12,7 +12,10 @@ <tbody class="settings"> <tr><td colspan="2"><h3><wicket:message key="gb.general"></wicket:message> <small><wicket:message key="gb.generalDescription"></wicket:message></small></h3></td></tr> <tr><th><wicket:message key="gb.teamName"></wicket:message></th><td class="edit"><input type="text" wicket:id="name" id="name" size="30" tabindex="1" /></td></tr> <tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="mailingLists" size="40" tabindex="2" /></td></tr> <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canAdmin" tabindex="2" /> <span class="help-inline"><wicket:message key="gb.canAdminDescription"></wicket:message></span></label></td></tr> <tr><th><wicket:message key="gb.canCreate"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canCreate" tabindex="3" /> <span class="help-inline"><wicket:message key="gb.canCreateDescription"></wicket:message></span></label></td></tr> <tr><th><wicket:message key="gb.canFork"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canFork" tabindex="4" /> <span class="help-inline"><wicket:message key="gb.canForkDescription"></wicket:message></span></label></td></tr> <tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="mailingLists" size="40" tabindex="5" /></td></tr> <tr><td colspan="2" style="padding-top:15px;"><h3><wicket:message key="gb.accessPermissions"></wicket:message> <small><wicket:message key="gb.accessPermissionsForTeamDescription"></wicket:message></small></h3></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.teamMembers"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr> <tr><td colspan="2"><hr></hr></td></tr> @@ -20,7 +23,7 @@ <tr><td colspan="2" style="padding-top:10px;"><h3><wicket:message key="gb.hookScripts"></wicket:message> <small><wicket:message key="gb.hookScriptsDescription"></wicket:message></small></h3></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.preReceiveScripts"></wicket:message><p></p><span wicket:id="inheritedPreReceive"></span></th><td style="padding:2px;"><span wicket:id="preReceiveScripts"></span></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.postReceiveScripts"></wicket:message><p></p><span wicket:id="inheritedPostReceive"></span></th><td style="padding:2px;"><span wicket:id="postReceiveScripts"></span></td></tr> <tr><td colspan='2'><div class="form-actions"><input class="btn btn-primary" type="submit" value="Save" wicket:message="value:gb.save" wicket:id="save" tabindex="3" /> <input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" tabindex="4" /></div></td></tr> <tr><td colspan='2'><div class="form-actions"><input class="btn btn-primary" type="submit" value="Save" wicket:message="value:gb.save" wicket:id="save" tabindex="6" /> <input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" tabindex="7" /></div></td></tr> </tbody> </table> </form> src/com/gitblit/wicket/pages/EditTeamPage.java
@@ -27,6 +27,7 @@ import org.apache.wicket.behavior.SimpleAttributeModifier; import org.apache.wicket.extensions.markup.html.form.palette.Palette; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.model.CompoundPropertyModel; @@ -222,6 +223,9 @@ // field names reflective match TeamModel fields form.add(new TextField<String>("name")); form.add(new CheckBox("canAdmin")); form.add(new CheckBox("canFork")); form.add(new CheckBox("canCreate")); form.add(users.setEnabled(editMemberships)); mailingLists = new Model<String>(teamModel.mailingLists == null ? "" : StringUtils.flattenStrings(teamModel.mailingLists, " ")); src/com/gitblit/wicket/pages/EditUserPage.html
@@ -17,8 +17,8 @@ <tr><th><wicket:message key="gb.displayName"></wicket:message></th><td class="edit"><input type="text" wicket:id="displayName" size="30" tabindex="4" /></td></tr> <tr><th><wicket:message key="gb.emailAddress"></wicket:message></th><td class="edit"><input type="text" wicket:id="emailAddress" size="30" tabindex="5" /></td></tr> <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> <span class="help-inline"><wicket:message key="gb.canAdminDescription"></wicket:message></span></label></td></tr> <tr><th><wicket:message key="gb.canFork"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canFork" tabindex="7" /> <span class="help-inline"><wicket:message key="gb.canForkDescription"></wicket:message></span></label></td></tr> <tr><th><wicket:message key="gb.canCreate"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canCreate" tabindex="8" /> <span class="help-inline"><wicket:message key="gb.canCreateDescription"></wicket:message></span></label></td></tr> <tr><th><wicket:message key="gb.canCreate"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canCreate" tabindex="7" /> <span class="help-inline"><wicket:message key="gb.canCreateDescription"></wicket:message></span></label></td></tr> <tr><th><wicket:message key="gb.canFork"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canFork" tabindex="8" /> <span class="help-inline"><wicket:message key="gb.canForkDescription"></wicket:message></span></label></td></tr> <tr><th><wicket:message key="gb.excludeFromFederation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="excludeFromFederation" tabindex="9" /> <span class="help-inline"><wicket:message key="gb.excludeFromFederationDescription"></wicket:message></span></label></td></tr> <tr><td colspan="2" style="padding-top:15px;"><h3><wicket:message key="gb.accessPermissions"></wicket:message> <small><wicket:message key="gb.accessPermissionsForUserDescription"></wicket:message></small></h3></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.teamMemberships"></wicket:message></th><td style="padding:2px;"><span wicket:id="teams"></span></td></tr> src/com/gitblit/wicket/pages/RepositoryPage.java
@@ -248,7 +248,7 @@ // user not allowed to fork or fork already exists or repo forbids forking add(new ExternalLink("forkLink", "").setVisible(false)); if (user.canFork && !model.allowForks) { if (user.canFork() && !model.allowForks) { // show forks prohibited indicator Fragment wc = new Fragment("forksProhibitedIndicator", "forksProhibitedFragment", this); Label lbl = new Label("forksProhibited", getString("gb.forksProhibited")); src/com/gitblit/wicket/pages/UserPage.java
@@ -101,7 +101,7 @@ add(new GravatarImage("gravatar", person, 210)); UserModel sessionUser = GitBlitWebSession.get().getUser(); if (sessionUser != null && user.canCreate && sessionUser.equals(user)) { if (sessionUser != null && user.canCreate() && sessionUser.equals(user)) { // user can create personal repositories add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class)); } else { src/com/gitblit/wicket/panels/RepositoriesPanel.java
@@ -92,7 +92,7 @@ }.setVisible(GitBlit.getBoolean(Keys.git.cacheRepositoryList, true))); managementLinks.add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class)); add(managementLinks); } else if (showManagement && user != null && user.canCreate) { } else if (showManagement && user != null && user.canCreate()) { // user can create personal repositories managementLinks = new Fragment("managementPanel", "personalLinks", this); managementLinks.add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class)); src/com/gitblit/wicket/panels/UsersPanel.java
@@ -81,7 +81,7 @@ item.add(editLink); } item.add(new Label("accesslevel", entry.canAdmin ? "administrator" : "")); item.add(new Label("accesslevel", entry.canAdmin() ? "administrator" : "")); item.add(new Label("teams", entry.teams.size() > 0 ? ("" + entry.teams.size()) : "")); item.add(new Label("repositories", entry.repositories.size() > 0 ? ("" + entry.repositories.size()) : "")); test-users.conf
@@ -4,4 +4,5 @@ role = "#admin" role = "#notfederated" [team "admins"] role = "#none" user = admin tests/com/gitblit/tests/PermissionsTest.java
@@ -2414,6 +2414,33 @@ assertFalse("user CAN delete!", user.canDelete(repository)); assertFalse("user CAN edit!", user.canEdit(repository)); } @Test public void testAdminTeamInheritance() throws Exception { UserModel user = new UserModel("test"); TeamModel team = new TeamModel("team"); team.canAdmin = true; user.teams.add(team); assertTrue("User did not inherit admin privileges", user.canAdmin()); } @Test public void testForkTeamInheritance() throws Exception { UserModel user = new UserModel("test"); TeamModel team = new TeamModel("team"); team.canFork = true; user.teams.add(team); assertTrue("User did not inherit fork privileges", user.canFork()); } @Test public void testCreateTeamInheritance() throws Exception { UserModel user = new UserModel("test"); TeamModel team = new TeamModel("team"); team.canCreate= true; user.teams.add(team); assertTrue("User did not inherit create privileges", user.canCreate()); } }