From: James Moger Date: Wed, 10 Oct 2012 04:05:34 +0000 (-0400) Subject: Finer-grained repository access permissions (issue 36) X-Git-Tag: v1.2.0~173 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=20714aee0d2d2a989d93d6065e081aed8ac85fbf;p=gitblit.git Finer-grained repository access permissions (issue 36) Implemented discrete repository access permissions to replace the really primitive course-grained permissions used to this point. This implementation allows for finer-grained access control, but still falls short of integrated, branch-based permissions sought by some. Access permissions follow the conventions established by Gitosis and Gitolite so they should feel immediately comfortable to experienced users. This permissions infrastructure is complete and works exactly as expected. Unfortunately, there is no ui in this commit to change permissions, that will be forthcoming. In the meantime, Gitblit hot-reloads users.conf so the permissions can be manipulated at runtime with a text editor. The following per-repository permissions are now supported: - V (view in web ui, RSS feeds, download zip) - R (clone) - RW (clone and push) - RWC (clone and push with ref creation) - RWD (clone and push with ref creation, deletion) - RW+ (clone and push with ref creation, deletion, rewind) And a users.conf entry looks something like this: [user "hannibal"] password = bossman repository = RWD:topsecret.git --- diff --git a/docs/01_features.mkd b/docs/01_features.mkd index 2baacf20..e1c0afa4 100644 --- a/docs/01_features.mkd +++ b/docs/01_features.mkd @@ -1,12 +1,21 @@ ## Standard Features (GO/WAR) - JGit SmartHTTP servlet - Browser and git client authentication -- Four *per-repository* access control configurations with a Read-Only control flag +- Four *per-repository* access restriction configurations with a Read-Only control flag - ![anonymous](blank.png) *Anonymous View, Clone & Push* - ![push](lock_go_16x16.png) *Authenticated Push* - ![clone](lock_pull_16x16.png) *Authenticated Clone & Push* - ![view](shield_16x16.png) *Authenticated View, Clone & Push* - ![freeze](cold_16x16.png) Freeze repository (i.e. deny push, make read-only) +- Six *per-user/team* repository access permissions + - **V** (view in web ui, RSS feeds, download zip) + - **R** (clone) + - **RW** (clone and push) + - **RWC** (clone and push with ref creation) + - **RWD** (clone and push with ref creation, deletion) + - **RW+** (clone and push with ref creation, deletion, rewind) +- Optional feature to allow users to create personal repositories +- Optional feature to fork a repository to a personal repository - Ability to federate with one or more other Gitblit instances - RSS/JSON RPC interface - Java/Swing Gitblit Manager tool @@ -38,7 +47,7 @@ - Single text file for users configuration - Optional utility pages - ![docs](book_16x16.png) Docs page which enumerates all Markdown files within a repository - - ![tickets](bug_16x16.png) Ticgit ticket pages *(based on last MIT release bf57b032 2009-01-27)* + - ![tickets](bug_16x16.png) **readonly** Ticgit ticket pages *(based on last MIT release bf57b032 2009-01-27)* - Translations - English - Japanese diff --git a/docs/01_setup.mkd b/docs/01_setup.mkd index fa1bcd90..1cebb3b7 100644 --- a/docs/01_setup.mkd +++ b/docs/01_setup.mkd @@ -244,6 +244,25 @@ All repositories created with Gitblit are *bare* and will automatically have *.g #### Repository Owner The *Repository Owner* has the special permission of being able to edit a repository through the web UI. The Repository Owner is not permitted to rename the repository, delete the repository, or reassign ownership to another user. +### Access Restrictions and Access Permissions +![permissions matrix](permissions_matrix.png "Permissions and Restrictions") + +#### Discrete Permissions (Gitblit v1.2.0+) + +Since v1.2.0, Gitblit supports more discrete permissions. While Gitblit does not offer a built-in solution for branch-based permissions like Gitolite, it does allow for the following repository access permissions: + +- **V** (view in web ui, RSS feeds, download zip) +- **R** (clone) +- **RW** (clone and push) +- **RWC** (clone and push with ref creation) +- **RWD** (clone and push with ref creation, deletion) +- **RW+** (clone and push with ref creation, deletion, rewind) + +#### No-So-Discrete Permissions (Gitblit <= v1.1.0) + +Prior to v1.2.0, Gitblit had two main access permission groupings: +What you were permitted to do as an anonymous user and then **RW+** for any permitted user. + ### Teams Since v0.8.0, Gitblit supports *teams* for the original `users.properties` user service and the current default user service `users.conf`. Teams have assigned users and assigned repositories. A user can be a member of multiple teams and a repository may belong to multiple teams. This allows the administrator to quickly add a user to a team without having to keep track of all the appropriate repositories. @@ -257,11 +276,12 @@ The `users.conf` file uses a Git-style configuration format: password = admin role = "#admin" role = "#notfederated" - repository = repo1.git - repository = repo2.git + repository = RW+:repo1.git + repository = RW+:repo2.git [user "hannibal"] password = bossman + repository = RWD:topsecret.git [user "faceman"] password = vanity @@ -277,7 +297,7 @@ The `users.conf` file uses a Git-style configuration format: user = faceman user = murdock user = babaracus - repository = topsecret.git + repository = RW:topsecret.git mailingList = list@ateam.org postReceiveScript = sendmail @@ -291,15 +311,49 @@ The format of `users.properties` loosely follows Jetty's convention for HashReal username=password,role1,role2,role3... @teamname=&mailinglist,!username1,!username2,!username3,repository1,repository2,repository3... -#### Usernames +### Usernames Usernames must be unique and are case-insensitive. Whitespace is illegal. -#### Passwords +### Passwords User passwords are CASE-SENSITIVE and may be *plain*, *md5*, or *combined-md5* formatted (see `gitblit.properties` -> *realm.passwordStorage*). -#### User Roles -There are two actual *roles* in Gitblit: *#admin*, which grants administrative powers to that user, and *#notfederated*, which prevents an account from being pulled by another Gitblit instance. Administrators automatically have access to all repositories. All other *roles* are repository names. If a repository is access-restricted, the user must have the repository's name within his/her roles to bypass the access restriction. This is how users are granted access to a restricted repository. +### User Roles +There are four actual *roles* in Gitblit: + +- *#admin*, which grants administrative powers to that user +- *#notfederated*, which prevents an account from being pulled by another Gitblit instance +- *#create*, which allows the user the power to create personal repositories +- *#fork*, which allows the user to create a personal fork of an existing Gitblit-hosted repository + +Administrators automatically have access to all repositories. All other *roles* are repository permissions. If a repository is access-restricted, the user must have the repository's name within his/her roles to bypass the access restriction. This is how users are granted access to a restricted repository. + +**NOTE:** +The following roles are equivalent: + +- myrepo.git +- RW+:myrepo.git + +This is to preserve backwards-compatibility with Gitblit <= 1.1.0 which granted rewind power to all access-permitted users. + +### Personal Repositories & Forks + +Personal Repositories and Forks are related but are controlled individually. + +#### Creating a Personal Repository +A user may be granted the power to create personal repositories by specifying the *#create* role through the web ui or through the RPC mechanism via the Gitblit Manager. Personal repositories are exactly like common/shared repositories except that the owner has a few additional administrative powers for that repository, like rename and delete. + +#### Creating a Fork +A user may also be granted the power to fork an existing repository hosted on your Gitblit server to their own personal clone by specifying the *#fork* role through the web ui or via the Gitblit Manager. + +Forks are mostly likely personal repositories or common/shared repositories except for two important differences: + +1. Forks inherit a view/clone access list from the origin repository. +i.e. if Team A has clone access to the origin repository, then by default Team A also has clone access to the fork. This is to facilitate collaboration. +2. Forks are always listed in the fork network, regardless of any access restriction set on the fork. +In other words, if you fork *RepoA.git* to *~me/RepoA.git* and then set the access restriction of *~me/RepoA.git* to *Authenticated View, Clone, & Push* your fork will still be listed in the fork network for *RepoA.git*. + +If you really must have an invisible fork, the clone it locally, create a new personal repository for your invisible fork, and push it back to that personal repository. ## Alternative Authentication and Authorization diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd index 31c503c0..bb9b7340 100644 --- a/docs/04_releases.mkd +++ b/docs/04_releases.mkd @@ -17,18 +17,26 @@ If you are updating from an earlier release AND you have indexed branches with t - Fixed connection leak in LDAPUserService (issue 139) - Fixed bug in commit page where changes to a submodule threw a null pointer exception (issue 132) - Fixed bug in the diff view for filenames that have non-ASCII characters (issue 128) -- Fix missing translations in Gitblit Manager (issue 145) #### additions -- Added simple project pages. A project is a subfolder off the *git.repositoriesFolder*. +- Implemented discrete repository permissions (issue 36) + - V (view in web ui, RSS feeds, download zip) + - R (clone) + - RW (clone and push) + - RWC (clone and push with ref creation) + - RWD (clone and push with ref creation, deletion) + - RW+ (clone and push with ref creation, deletion, rewind) +While not as sophisticated as Gitolite, this does give finer access controls. These permissions fit in cleanly with the existing users.conf and users.properties files. In Gitblit <= 1.1.0, all your existing user accounts have RW+ access. If you are upgrading to 1.2.0, the RW+ access is *preserved* and you will have to lower/adjust accordingly. +- Added DELETE, CREATE, and NON-FAST-FORWARD ref change logging - Added support for personal repositories. Personal repositories can be created by accounts with the *create* permission and are stored in *git.repositoriesFolder/~username*. Each user with personal repositories will have a user page, something like the GitHub profile page. Personal repositories have all the same features as common repositories, except personal repositories can be renamed by their owner. - Added support for server-side forking of a repository to a personal repository (issue 137) -In order to fork a repository, the user account must have the *fork* permission **and** the repository must *allow forks*. The clone inherits the access restrictions of its origin. i.e. if Team A has access to the origin repository, then by default Team A also has access to the fork. This is to facilitate collaboration. The fork owner may change access to the fork and add/remove users/teams, etc as required __however__ it should be noted that all personal forks will be enumerated in the fork network regardless of access view restrictions. If you really must have an invisible fork, the clone it locally, create a new repository for your invisible fork, and push it back. +In order to fork a repository, the user account must have the *fork* permission **and** the repository must *allow forks*. The clone inherits the access list of its origin. i.e. if Team A has clone access to the origin repository, then by default Team A also has clone access to the fork. This is to facilitate collaboration. The fork owner may change access to the fork and add/remove users/teams, etc as required however it should be noted that all personal forks will be enumerated in the fork network regardless of access view restrictions. If you really must have an invisible fork, the clone it locally, create a new repository for your invisible fork, and push it back to Gitblit. +- Added simple project pages. A project is a subfolder off the *git.repositoriesFolder*. - Added support for X-Forwarded-Context for Apache subdomain proxy configurations (issue 135) - Delete branch feature (issue 121, Github/ajermakovics) -- Added line links to blob view at the expense of zebra striping (issue 130) +- Added line links to blob view (issue 130) - Added RedmineUserService (github/mallowlabs) #### changes diff --git a/docs/permissions_matrix.ods b/docs/permissions_matrix.ods new file mode 100644 index 00000000..6df0b4db Binary files /dev/null and b/docs/permissions_matrix.ods differ diff --git a/docs/permissions_matrix.png b/docs/permissions_matrix.png new file mode 100644 index 00000000..d463ae11 Binary files /dev/null and b/docs/permissions_matrix.png differ diff --git a/src/com/gitblit/ConfigUserService.java b/src/com/gitblit/ConfigUserService.java index 831ede9b..d2740094 100644 --- a/src/com/gitblit/ConfigUserService.java +++ b/src/com/gitblit/ConfigUserService.java @@ -33,6 +33,7 @@ import org.eclipse.jgit.util.FS; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.gitblit.Constants.AccessPermission; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; import com.gitblit.utils.ArrayUtils; @@ -267,6 +268,55 @@ public class ConfigUserService implements IUserService { return updateUserModel(model.username, model); } + /** + * Updates/writes all specified user objects. + * + * @param models a list of user models + * @return true if update is successful + * @since 1.2.0 + */ + @Override + public boolean updateUserModels(List models) { + try { + read(); + for (UserModel model : models) { + UserModel originalUser = users.remove(model.username.toLowerCase()); + users.put(model.username.toLowerCase(), model); + // null check on "final" teams because JSON-sourced UserModel + // can have a null teams object + if (model.teams != null) { + for (TeamModel team : model.teams) { + TeamModel t = teams.get(team.name.toLowerCase()); + if (t == null) { + // new team + team.addUser(model.username); + teams.put(team.name.toLowerCase(), team); + } else { + // do not clobber existing team definition + // maybe because this is a federated user + t.addUser(model.username); + } + } + + // check for implicit team removal + if (originalUser != null) { + for (TeamModel team : originalUser.teams) { + if (!model.isTeamMember(team.name)) { + team.removeUser(model.username); + } + } + } + } + } + write(); + return true; + } catch (Throwable t) { + logger.error(MessageFormat.format("Failed to update user {0} models!", models.size()), + t); + } + return false; + } + /** * Updates/writes and replaces a complete user object keyed by username. * This method allows for renaming a user. @@ -413,7 +463,7 @@ public class ConfigUserService implements IUserService { read(); for (Map.Entry entry : teams.entrySet()) { TeamModel model = entry.getValue(); - if (model.hasRepository(role)) { + if (model.hasRepositoryPermission(role)) { list.add(model.name); } } @@ -447,10 +497,10 @@ public class ConfigUserService implements IUserService { for (TeamModel team : teams.values()) { // team has role, check against revised team list if (specifiedTeams.contains(team.name.toLowerCase())) { - team.addRepository(role); + team.addRepositoryPermission(role); } else { // remove role from team - team.removeRepository(role); + team.removeRepositoryPermission(role); } } @@ -494,6 +544,28 @@ public class ConfigUserService implements IUserService { return updateTeamModel(model.name, model); } + /** + * Updates/writes all specified team objects. + * + * @param models a list of team models + * @return true if update is successful + * @since 1.2.0 + */ + @Override + public boolean updateTeamModels(List models) { + try { + read(); + for (TeamModel team : models) { + teams.put(team.name.toLowerCase(), team); + } + write(); + return true; + } catch (Throwable t) { + logger.error(MessageFormat.format("Failed to update team {0} models!", models.size()), t); + } + return false; + } + /** * Updates/writes and replaces a complete team object keyed by teamname. * This method allows for renaming a team. @@ -602,7 +674,7 @@ public class ConfigUserService implements IUserService { read(); for (Map.Entry entry : users.entrySet()) { UserModel model = entry.getValue(); - if (model.hasRepository(role)) { + if (model.hasRepositoryPermission(role)) { list.add(model.username); } } @@ -623,6 +695,7 @@ public class ConfigUserService implements IUserService { * @return true if successful */ @Override + @Deprecated public boolean setUsernamesForRepositoryRole(String role, List usernames) { try { Set specifiedUsers = new HashSet(); @@ -636,10 +709,10 @@ public class ConfigUserService implements IUserService { for (UserModel user : users.values()) { // user has role, check against revised user list if (specifiedUsers.contains(user.username.toLowerCase())) { - user.addRepository(role); + user.addRepositoryPermission(role); } else { // remove role from user - user.removeRepository(role); + user.removeRepositoryPermission(role); } } @@ -665,17 +738,17 @@ public class ConfigUserService implements IUserService { read(); // identify users which require role rename for (UserModel model : users.values()) { - if (model.hasRepository(oldRole)) { - model.removeRepository(oldRole); - model.addRepository(newRole); + if (model.hasRepositoryPermission(oldRole)) { + AccessPermission permission = model.removeRepositoryPermission(oldRole); + model.setRepositoryPermission(newRole, permission); } } // identify teams which require role rename for (TeamModel model : teams.values()) { - if (model.hasRepository(oldRole)) { - model.removeRepository(oldRole); - model.addRepository(newRole); + if (model.hasRepositoryPermission(oldRole)) { + AccessPermission permission = model.removeRepositoryPermission(oldRole); + model.setRepositoryPermission(newRole, permission); } } // persist changes @@ -701,12 +774,12 @@ public class ConfigUserService implements IUserService { // identify users which require role rename for (UserModel user : users.values()) { - user.removeRepository(role); + user.removeRepositoryPermission(role); } // identify teams which require role rename for (TeamModel team : teams.values()) { - team.removeRepository(role); + team.removeRepositoryPermission(role); } // persist changes @@ -768,21 +841,44 @@ public class ConfigUserService implements IUserService { config.setStringList(USER, model.username, ROLE, roles); // repository memberships - // null check on "final" repositories because JSON-sourced UserModel - // can have a null repositories object - if (!ArrayUtils.isEmpty(model.repositories)) { - config.setStringList(USER, model.username, REPOSITORY, new ArrayList( - model.repositories)); + if (model.permissions == null) { + // null check on "final" repositories because JSON-sourced UserModel + // can have a null repositories object + if (!ArrayUtils.isEmpty(model.repositories)) { + config.setStringList(USER, model.username, REPOSITORY, new ArrayList( + model.repositories)); + } + } else { + // discrete repository permissions + List permissions = new ArrayList(); + for (Map.Entry entry : model.permissions.entrySet()) { + if (entry.getValue().exceeds(AccessPermission.NONE)) { + permissions.add(entry.getValue().asRole(entry.getKey())); + } + } + config.setStringList(USER, model.username, REPOSITORY, permissions); } } // write teams for (TeamModel model : teams.values()) { - // null check on "final" repositories because JSON-sourced TeamModel - // can have a null repositories object - if (!ArrayUtils.isEmpty(model.repositories)) { - config.setStringList(TEAM, model.name, REPOSITORY, new ArrayList( - model.repositories)); + if (model.permissions == null) { + // null check on "final" repositories because JSON-sourced TeamModel + // can have a null repositories object + if (!ArrayUtils.isEmpty(model.repositories)) { + config.setStringList(TEAM, model.name, REPOSITORY, new ArrayList( + model.repositories)); + } + } else { + // discrete repository permissions + List permissions = new ArrayList(); + for (Map.Entry entry : model.permissions.entrySet()) { + if (entry.getValue().exceeds(AccessPermission.NONE)) { + // code:repository (e.g. RW+:~james/myrepo.git + permissions.add(entry.getValue().asRole(entry.getKey())); + } + } + config.setStringList(TEAM, model.name, REPOSITORY, permissions); } // null check on "final" users because JSON-sourced TeamModel @@ -872,7 +968,7 @@ public class ConfigUserService implements IUserService { Set repositories = new HashSet(Arrays.asList(config .getStringList(USER, username, REPOSITORY))); for (String repository : repositories) { - user.addRepository(repository); + user.addRepositoryPermission(repository); } // update cache @@ -886,7 +982,7 @@ public class ConfigUserService implements IUserService { Set teamnames = config.getSubsections(TEAM); for (String teamname : teamnames) { TeamModel team = new TeamModel(teamname); - team.addRepositories(Arrays.asList(config.getStringList(TEAM, teamname, + team.addRepositoryPermissions(Arrays.asList(config.getStringList(TEAM, teamname, REPOSITORY))); team.addUsers(Arrays.asList(config.getStringList(TEAM, teamname, USER))); team.addMailingLists(Arrays.asList(config.getStringList(TEAM, teamname, diff --git a/src/com/gitblit/Constants.java b/src/com/gitblit/Constants.java index c831c42d..ed48bd27 100644 --- a/src/com/gitblit/Constants.java +++ b/src/com/gitblit/Constants.java @@ -15,6 +15,10 @@ */ package com.gitblit; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Constant values used by Gitblit. @@ -309,4 +313,72 @@ public class Constants { return null; } } + + /** + * The access permissions available for a repository. + */ + public static enum AccessPermission { + NONE("N"), VIEW("V"), CLONE("R"), PUSH("RW"), CREATE("RWC"), DELETE("RWD"), REWIND("RW+"); + + public static AccessPermission LEGACY = REWIND; + + public final String code; + + private AccessPermission(String code) { + this.code = code; + } + + public boolean atLeast(AccessPermission perm) { + return ordinal() >= perm.ordinal(); + } + + public boolean exceeds(AccessPermission perm) { + return ordinal() > perm.ordinal(); + } + + public String asRole(String repository) { + return code + ":" + repository; + } + + @Override + public String toString() { + return code; + } + + public static AccessPermission permissionFromRole(String role) { + String [] fields = role.split(":", 2); + if (fields.length == 1) { + // legacy/undefined assume full permissions + return AccessPermission.LEGACY; + } else { + // code:repository + return AccessPermission.fromCode(fields[0]); + } + } + + public static String repositoryFromRole(String role) { + String [] fields = role.split(":", 2); + if (fields.length == 1) { + // legacy/undefined assume full permissions + return role; + } else { + // code:repository + return fields[1]; + } + } + + public static AccessPermission fromCode(String code) { + for (AccessPermission perm : values()) { + if (perm.code.equalsIgnoreCase(code)) { + return perm; + } + } + return AccessPermission.NONE; + } + } + + @Documented + @Retention(RetentionPolicy.RUNTIME) + public @interface Unused { + } } diff --git a/src/com/gitblit/DownloadZipFilter.java b/src/com/gitblit/DownloadZipFilter.java index e515b55e..225e5e11 100644 --- a/src/com/gitblit/DownloadZipFilter.java +++ b/src/com/gitblit/DownloadZipFilter.java @@ -91,7 +91,7 @@ public class DownloadZipFilter extends AccessRestrictionFilter { */ @Override protected boolean canAccess(RepositoryModel repository, UserModel user, String action) { - return user.canAccessRepository(repository); + return user.canView(repository); } } diff --git a/src/com/gitblit/FederationPullExecutor.java b/src/com/gitblit/FederationPullExecutor.java index 7b9c55ba..03109dea 100644 --- a/src/com/gitblit/FederationPullExecutor.java +++ b/src/com/gitblit/FederationPullExecutor.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -41,6 +42,7 @@ import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.FederationPullStatus; import com.gitblit.Constants.FederationStrategy; import com.gitblit.GitBlitException.ForbiddenException; @@ -333,10 +335,20 @@ public class FederationPullExecutor implements Runnable { // reparent all repository permissions if the local // repositories are stored within subfolders if (!StringUtils.isEmpty(registrationFolder)) { - List permissions = new ArrayList(user.repositories); - user.repositories.clear(); - for (String permission : permissions) { - user.addRepository(registrationFolder + "/" + permission); + if (user.permissions != null && user.permissions.size() > 0) { + // pulling from >= 1.2 version + Map copy = new HashMap(user.permissions); + user.permissions.clear(); + for (Map.Entry entry : copy.entrySet()) { + user.setRepositoryPermission(registrationFolder + "/" + entry.getKey(), entry.getValue()); + } + } else { + // pulling from <= 1.1 version + List permissions = new ArrayList(user.repositories); + user.repositories.clear(); + for (String permission : permissions) { + user.addRepositoryPermission(registrationFolder + "/" + permission); + } } } @@ -347,8 +359,17 @@ public class FederationPullExecutor implements Runnable { GitBlit.self().updateUserModel(user.username, user, true); } else { // update repository permissions of local user - for (String repository : user.repositories) { - localUser.addRepository(repository); + if (user.permissions != null && user.permissions.size() > 0) { + // pulling from >= 1.2 version + Map copy = new HashMap(user.permissions); + for (Map.Entry entry : copy.entrySet()) { + localUser.setRepositoryPermission(entry.getKey(), entry.getValue()); + } + } else { + // pulling from <= 1.1 version + for (String repository : user.repositories) { + localUser.addRepositoryPermission(repository); + } } localUser.password = user.password; localUser.canAdmin = user.canAdmin; @@ -369,12 +390,16 @@ public class FederationPullExecutor implements Runnable { // update team repositories TeamModel remoteTeam = user.getTeam(teamname); - if (remoteTeam != null && !ArrayUtils.isEmpty(remoteTeam.repositories)) { - int before = team.repositories.size(); - team.addRepositories(remoteTeam.repositories); - int after = team.repositories.size(); - if (after > before) { - // repository count changed, update + if (remoteTeam != null) { + if (remoteTeam.permissions != null) { + // pulling from >= 1.2 + for (Map.Entry entry : remoteTeam.permissions.entrySet()){ + team.setRepositoryPermission(entry.getKey(), entry.getValue()); + } + GitBlit.self().updateTeamModel(teamname, team, false); + } else if(!ArrayUtils.isEmpty(remoteTeam.repositories)) { + // pulling from <= 1.1 + team.addRepositoryPermissions(remoteTeam.repositories); GitBlit.self().updateTeamModel(teamname, team, false); } } diff --git a/src/com/gitblit/FileUserService.java b/src/com/gitblit/FileUserService.java index f4394696..c06266dc 100644 --- a/src/com/gitblit/FileUserService.java +++ b/src/com/gitblit/FileUserService.java @@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.gitblit.Constants.AccessPermission; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; import com.gitblit.utils.ArrayUtils; @@ -243,7 +244,7 @@ public class FileUserService extends FileSettings implements IUserService { } break; default: - model.addRepository(role); + model.addRepositoryPermission(role); } } // set the teams for the user @@ -266,6 +267,29 @@ public class FileUserService extends FileSettings implements IUserService { return updateUserModel(model.username, model); } + /** + * Updates/writes all specified user objects. + * + * @param model a list of user models + * @return true if update is successful + * @since 1.2.0 + */ + @Override + public boolean updateUserModels(List models) { + try { + Properties allUsers = read(); + for (UserModel model : models) { + updateUserCache(allUsers, model.username, model); + } + write(allUsers); + return true; + } catch (Throwable t) { + logger.error(MessageFormat.format("Failed to update {0} user models!", models.size()), + t); + } + return false; + } + /** * Updates/writes and replaces a complete user object keyed by username. * This method allows for renaming a user. @@ -280,8 +304,43 @@ public class FileUserService extends FileSettings implements IUserService { public boolean updateUserModel(String username, UserModel model) { try { Properties allUsers = read(); + updateUserCache(allUsers, username, model); + write(allUsers); + return true; + } catch (Throwable t) { + logger.error(MessageFormat.format("Failed to update user model {0}!", model.username), + t); + } + return false; + } + + /** + * Updates/writes and replaces a complete user object keyed by username. + * This method allows for renaming a user. + * + * @param username + * the old username + * @param model + * the user object to use for username + * @return true if update is successful + */ + private boolean updateUserCache(Properties allUsers, String username, UserModel model) { + try { UserModel oldUser = getUserModel(username); - ArrayList roles = new ArrayList(model.repositories); + List roles; + if (model.permissions == null) { + // legacy, use repository list + roles = new ArrayList(model.repositories); + } else { + // discrete repository permissions + roles = new ArrayList(); + for (Map.Entry entry : model.permissions.entrySet()) { + if (entry.getValue().exceeds(AccessPermission.NONE)) { + // code:repository (e.g. RW+:~james/myrepo.git + roles.add(entry.getValue().asRole(entry.getKey())); + } + } + } // Permissions if (model.canAdmin) { @@ -336,8 +395,6 @@ public class FileUserService extends FileSettings implements IUserService { } } } - - write(allUsers); return true; } catch (Throwable t) { logger.error(MessageFormat.format("Failed to update user model {0}!", model.username), @@ -552,8 +609,8 @@ public class FileUserService extends FileSettings implements IUserService { String[] roles = value.split(","); // skip first value (password) for (int i = 1; i < roles.length; i++) { - String r = roles[i]; - if (r.equalsIgnoreCase(oldRole)) { + String repository = AccessPermission.repositoryFromRole(roles[i]); + if (repository.equalsIgnoreCase(oldRole)) { needsRenameRole.add(username); break; } @@ -573,9 +630,13 @@ public class FileUserService extends FileSettings implements IUserService { // skip first value (password) for (int i = 1; i < values.length; i++) { - String value = values[i]; - if (!value.equalsIgnoreCase(oldRole)) { - sb.append(value); + String repository = AccessPermission.repositoryFromRole(values[i]); + if (repository.equalsIgnoreCase(oldRole)) { + AccessPermission permission = AccessPermission.permissionFromRole(values[i]); + sb.append(permission.asRole(newRole)); + sb.append(','); + } else { + sb.append(values[i]); sb.append(','); } } @@ -612,9 +673,9 @@ public class FileUserService extends FileSettings implements IUserService { String value = allUsers.getProperty(username); String[] roles = value.split(","); // skip first value (password) - for (int i = 1; i < roles.length; i++) { - String r = roles[i]; - if (r.equalsIgnoreCase(role)) { + for (int i = 1; i < roles.length; i++) { + String repository = AccessPermission.repositoryFromRole(roles[i]); + if (repository.equalsIgnoreCase(role)) { needsDeleteRole.add(username); break; } @@ -630,10 +691,10 @@ public class FileUserService extends FileSettings implements IUserService { sb.append(password); sb.append(','); // skip first value (password) - for (int i = 1; i < values.length; i++) { - String value = values[i]; - if (!value.equalsIgnoreCase(role)) { - sb.append(value); + for (int i = 1; i < values.length; i++) { + String repository = AccessPermission.repositoryFromRole(values[i]); + if (!repository.equalsIgnoreCase(role)) { + sb.append(values[i]); sb.append(','); } } @@ -722,7 +783,7 @@ public class FileUserService extends FileSettings implements IUserService { repositories.add(role); } } - team.addRepositories(repositories); + team.addRepositoryPermissions(repositories); team.addUsers(users); team.addMailingLists(mailingLists); team.preReceiveScripts.addAll(preReceive); @@ -912,6 +973,27 @@ public class FileUserService extends FileSettings implements IUserService { public boolean updateTeamModel(TeamModel model) { return updateTeamModel(model.name, model); } + + /** + * Updates/writes all specified team objects. + * + * @param models a list of team models + * @return true if update is successful + * @since 1.2.0 + */ + public boolean updateTeamModels(List models) { + try { + Properties allUsers = read(); + for (TeamModel model : models) { + updateTeamCache(allUsers, model.name, model); + } + write(allUsers); + return true; + } catch (Throwable t) { + logger.error(MessageFormat.format("Failed to update {0} team models!", models.size()), t); + } + return false; + } /** * Updates/writes and replaces a complete team object keyed by teamname. @@ -939,12 +1021,30 @@ public class FileUserService extends FileSettings implements IUserService { private void updateTeamCache(Properties allUsers, String teamname, TeamModel model) { StringBuilder sb = new StringBuilder(); - if (!ArrayUtils.isEmpty(model.repositories)) { - for (String repository : model.repositories) { - sb.append(repository); - sb.append(','); + List roles; + if (model.permissions == null) { + // legacy, use repository list + if (model.repositories != null) { + roles = new ArrayList(model.repositories); + } else { + roles = new ArrayList(); + } + } else { + // discrete repository permissions + roles = new ArrayList(); + for (Map.Entry entry : model.permissions.entrySet()) { + if (entry.getValue().exceeds(AccessPermission.NONE)) { + // code:repository (e.g. RW+:~james/myrepo.git + roles.add(entry.getValue().asRole(entry.getKey())); + } } } + + for (String role : roles) { + sb.append(role); + sb.append(','); + } + if (!ArrayUtils.isEmpty(model.users)) { for (String user : model.users) { sb.append('!'); diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java index 7fbd3efd..8c6d9eba 100644 --- a/src/com/gitblit/GitBlit.java +++ b/src/com/gitblit/GitBlit.java @@ -69,6 +69,7 @@ import org.eclipse.jgit.util.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.FederationRequest; @@ -618,6 +619,7 @@ public class GitBlit implements ServletContextListener { * @param usernames * @return true if successful */ + @Deprecated public boolean setRepositoryUsers(RepositoryModel repository, List repositoryUsers) { return userService.setUsernamesForRepositoryRole(repository.name, repositoryUsers); } @@ -699,6 +701,7 @@ public class GitBlit implements ServletContextListener { * @param teamnames * @return true if successful */ + @Deprecated public boolean setRepositoryTeams(RepositoryModel repository, List repositoryTeams) { return userService.setTeamnamesForRepositoryRole(repository.name, repositoryTeams); } @@ -957,14 +960,13 @@ public class GitBlit implements ServletContextListener { if (model == null) { return null; } - if (model.accessRestriction.atLeast(AccessRestrictionType.VIEW)) { - if (user != null && user.canAccessRepository(model)) { - return model; - } - return null; - } else { + if (user == null) { + user = UserModel.ANONYMOUS; + } + if (user.canView(model)) { return model; } + return null; } /** @@ -1224,11 +1226,7 @@ public class GitBlit implements ServletContextListener { } model.hasCommits = JGitUtils.hasCommits(r); model.lastChange = JGitUtils.getLastChange(r); - if (repositoryName.indexOf('/') == -1) { - model.projectPath = ""; - } else { - model.projectPath = repositoryName.substring(0, repositoryName.indexOf('/')); - } + model.projectPath = StringUtils.getFirstPathElement(repositoryName); StoredConfig config = r.getConfig(); boolean hasOrigin = !StringUtils.isEmpty(config.getString("remote", "origin", "url")); @@ -1449,6 +1447,9 @@ public class GitBlit implements ServletContextListener { */ private void closeRepository(String repositoryName) { Repository repository = getRepository(repositoryName); + if (repository == null) { + return; + } RepositoryCache.close(repository); // assume 2 uses in case reflection fails @@ -1756,7 +1757,7 @@ public class GitBlit implements ServletContextListener { clearRepositoryMetadataCache(repositoryName); RepositoryModel model = removeFromCachedRepositoryList(repositoryName); - if (!ArrayUtils.isEmpty(model.forks)) { + if (model != null && !ArrayUtils.isEmpty(model.forks)) { resetRepositoryListCache(); } @@ -2646,26 +2647,46 @@ public class GitBlit implements ServletContextListener { // create a Gitblit repository model for the clone RepositoryModel cloneModel = repository.cloneAs(cloneName); + // owner has REWIND/RW+ permissions cloneModel.owner = user.username; updateRepositoryModel(cloneName, cloneModel, false); - if (AuthorizationControl.NAMED.equals(cloneModel.authorizationControl)) { - // add the owner of the source repository to the clone's access list - if (!StringUtils.isEmpty(repository.owner)) { - UserModel owner = getUserModel(repository.owner); - if (owner != null) { - owner.repositories.add(cloneName); - updateUserModel(owner.username, owner, false); - } + // add the owner of the source repository to the clone's access list + if (!StringUtils.isEmpty(repository.owner)) { + UserModel originOwner = getUserModel(repository.owner); + if (originOwner != null) { + originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE); + updateUserModel(originOwner.username, originOwner, false); } + } - // inherit origin's access lists - List users = getRepositoryUsers(repository); - setRepositoryUsers(cloneModel, users); + // grant origin's user list clone permission to fork + List users = getRepositoryUsers(repository); + List cloneUsers = new ArrayList(); + for (String name : users) { + if (!name.equalsIgnoreCase(user.username)) { + UserModel cloneUser = getUserModel(name); + if (cloneUser.canClone(repository)) { + // origin user can clone origin, grant clone access to fork + cloneUser.setRepositoryPermission(cloneName, AccessPermission.CLONE); + } + cloneUsers.add(cloneUser); + } + } + userService.updateUserModels(cloneUsers); - List teams = getRepositoryTeams(repository); - setRepositoryTeams(cloneModel, teams); + // grant origin's team list clone permission to fork + List teams = getRepositoryTeams(repository); + List cloneTeams = new ArrayList(); + for (String name : teams) { + TeamModel cloneTeam = getTeamModel(name); + if (cloneTeam.canClone(repository)) { + // origin team can clone origin, grant clone access to fork + cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE); + } + cloneTeams.add(cloneTeam); } + userService.updateTeamModels(cloneTeams); // add this clone to the cached model addToCachedRepositoryList(cloneModel); diff --git a/src/com/gitblit/GitFilter.java b/src/com/gitblit/GitFilter.java index 8ce4d3a7..cfe4fe3f 100644 --- a/src/com/gitblit/GitFilter.java +++ b/src/com/gitblit/GitFilter.java @@ -147,33 +147,25 @@ public class GitFilter extends AccessRestrictionFilter { // Git Servlet disabled return false; } - boolean readOnly = repository.isFrozen; - if (readOnly || repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) { - boolean authorizedUser = user.canAccessRepository(repository); - if (action.equals(gitReceivePack)) { - // Push request - if (!readOnly && authorizedUser) { - // clone-restricted or push-authorized - return true; - } else { - // user is unauthorized to push to this repository - logger.warn(MessageFormat.format("user {0} is not authorized to push to {1}", - user.username, repository)); - return false; - } - } else if (action.equals(gitUploadPack)) { - // Clone request - boolean cloneRestricted = repository.accessRestriction - .atLeast(AccessRestrictionType.CLONE); - if (!cloneRestricted || (cloneRestricted && authorizedUser)) { - // push-restricted or clone-authorized - return true; - } else { - // user is unauthorized to clone this repository - logger.warn(MessageFormat.format("user {0} is not authorized to clone {1}", - user.username, repository)); - return false; - } + if (action.equals(gitReceivePack)) { + // Push request + if (user.canPush(repository)) { + return true; + } else { + // user is unauthorized to push to this repository + logger.warn(MessageFormat.format("user {0} is not authorized to push to {1}", + user.username, repository)); + return false; + } + } else if (action.equals(gitUploadPack)) { + // Clone request + if (user.canClone(repository)) { + return true; + } else { + // user is unauthorized to clone this repository + logger.warn(MessageFormat.format("user {0} is not authorized to clone {1}", + user.username, repository)); + return false; } } return true; diff --git a/src/com/gitblit/GitServlet.java b/src/com/gitblit/GitServlet.java index 2571693d..8e2326d4 100644 --- a/src/com/gitblit/GitServlet.java +++ b/src/com/gitblit/GitServlet.java @@ -105,6 +105,21 @@ public class GitServlet extends org.eclipse.jgit.http.server.GitServlet { ReceivePack rp = super.create(req, db); rp.setPreReceiveHook(hook); rp.setPostReceiveHook(hook); + + // determine pushing user + PersonIdent person = rp.getRefLogIdent(); + UserModel user = GitBlit.self().getUserModel(person.getName()); + if (user == null) { + // anonymous push, create a temporary usermodel + user = new UserModel(person.getName()); + } + + // enforce advanced ref permissions + RepositoryModel repository = GitBlit.self().getRepositoryModel(repositoryName); + rp.setAllowCreates(user.canCreateRef(repository)); + rp.setAllowDeletes(user.canDeleteRef(repository)); + rp.setAllowNonFastForwards(user.canRewindRef(repository)); + return rp; } }); @@ -209,7 +224,25 @@ public class GitServlet extends org.eclipse.jgit.http.server.GitServlet { scripts.addAll(repository.postReceiveScripts); UserModel user = getUserModel(rp); runGroovy(repository, user, commands, rp, scripts); - + for (ReceiveCommand cmd : commands) { + if (Result.OK.equals(cmd.getResult())) { + // add some logging for important ref changes + switch (cmd.getType()) { + case DELETE: + logger.info(MessageFormat.format("{0} DELETED {1} in {2} ({3})", user.username, cmd.getRefName(), repository.name, cmd.getOldId().name())); + break; + case CREATE: + logger.info(MessageFormat.format("{0} CREATED {1} in {2}", user.username, cmd.getRefName(), repository.name)); + break; + case UPDATE_NONFASTFORWARD: + logger.info(MessageFormat.format("{0} UPDATED NON-FAST-FORWARD {1} in {2} (from {3} to {4})", user.username, cmd.getRefName(), repository.name, cmd.getOldId().name(), cmd.getNewId().name())); + break; + default: + break; + } + } + } + // Experimental // runNativeScript(rp, "hooks/post-receive", commands); } diff --git a/src/com/gitblit/GitblitUserService.java b/src/com/gitblit/GitblitUserService.java index b4640b58..141ad8f1 100644 --- a/src/com/gitblit/GitblitUserService.java +++ b/src/com/gitblit/GitblitUserService.java @@ -167,6 +167,11 @@ public class GitblitUserService implements IUserService { return serviceImpl.updateUserModel(model); } + @Override + public boolean updateUserModels(List models) { + return serviceImpl.updateUserModels(models); + } + @Override public boolean updateUserModel(String username, UserModel model) { if (supportsCredentialChanges()) { @@ -232,6 +237,7 @@ public class GitblitUserService implements IUserService { } @Override + @Deprecated public boolean setTeamnamesForRepositoryRole(String role, List teamnames) { return serviceImpl.setTeamnamesForRepositoryRole(role, teamnames); } @@ -246,6 +252,11 @@ public class GitblitUserService implements IUserService { return serviceImpl.updateTeamModel(model); } + @Override + public boolean updateTeamModels(List models) { + return serviceImpl.updateTeamModels(models); + } + @Override public boolean updateTeamModel(String teamname, TeamModel model) { if (!supportsTeamMembershipChanges()) { @@ -275,6 +286,7 @@ public class GitblitUserService implements IUserService { } @Override + @Deprecated public boolean setUsernamesForRepositoryRole(String role, List usernames) { return serviceImpl.setUsernamesForRepositoryRole(role, usernames); } diff --git a/src/com/gitblit/IUserService.java b/src/com/gitblit/IUserService.java index 8822d024..059d648a 100644 --- a/src/com/gitblit/IUserService.java +++ b/src/com/gitblit/IUserService.java @@ -126,6 +126,15 @@ public interface IUserService { */ boolean updateUserModel(UserModel model); + /** + * Updates/writes all specified user objects. + * + * @param models a list of user models + * @return true if update is successful + * @since 1.2.0 + */ + boolean updateUserModels(List models); + /** * Adds/updates a user object keyed by username. This method allows for * renaming a user. @@ -205,7 +214,8 @@ public interface IUserService { * @param teamnames * @return true if successful * @since 0.8.0 - */ + */ + @Deprecated boolean setTeamnamesForRepositoryRole(String role, List teamnames); /** @@ -226,6 +236,15 @@ public interface IUserService { */ boolean updateTeamModel(TeamModel model); + /** + * Updates/writes all specified team objects. + * + * @param models a list of team models + * @return true if update is successful + * @since 1.2.0 + */ + boolean updateTeamModels(List models); + /** * Updates/writes and replaces a complete team object keyed by teamname. * This method allows for renaming a team. @@ -277,6 +296,7 @@ public interface IUserService { * @param usernames * @return true if successful */ + @Deprecated boolean setUsernamesForRepositoryRole(String role, List usernames); /** diff --git a/src/com/gitblit/PagesFilter.java b/src/com/gitblit/PagesFilter.java index c092c64d..11cdfa56 100644 --- a/src/com/gitblit/PagesFilter.java +++ b/src/com/gitblit/PagesFilter.java @@ -111,6 +111,6 @@ public class PagesFilter extends AccessRestrictionFilter { */ @Override protected boolean canAccess(RepositoryModel repository, UserModel user, String action) { - return user.canAccessRepository(repository); + return user.canView(repository); } } diff --git a/src/com/gitblit/SyndicationFilter.java b/src/com/gitblit/SyndicationFilter.java index 0dff1c87..61bf2258 100644 --- a/src/com/gitblit/SyndicationFilter.java +++ b/src/com/gitblit/SyndicationFilter.java @@ -113,7 +113,7 @@ public class SyndicationFilter extends AuthenticationFilter { return; } else { // check user access for request - if (user.canAdmin || user.canAccessRepository(model)) { + if (user.canView(model)) { // authenticated request permitted. // pass processing to the restricted servlet. newSession(authenticatedRequest, httpResponse); diff --git a/src/com/gitblit/models/RepositoryModel.java b/src/com/gitblit/models/RepositoryModel.java index caf7e7e4..914523df 100644 --- a/src/com/gitblit/models/RepositoryModel.java +++ b/src/com/gitblit/models/RepositoryModel.java @@ -88,7 +88,8 @@ public class RepositoryModel implements Serializable, Comparable(); - this.federationStrategy = FederationStrategy.FEDERATE_THIS; + this.federationStrategy = FederationStrategy.FEDERATE_THIS; + this.projectPath = StringUtils.getFirstPathElement(name); } public List getLocalBranches() { @@ -175,8 +176,8 @@ public class RepositoryModel implements Serializable, Comparable { // field names are reflectively mapped in EditTeam page public String name; public final Set users = new HashSet(); + // retained for backwards-compatibility with RPC clients + @Deprecated public final Set repositories = new HashSet(); + public final Map permissions = new HashMap(); public final Set mailingLists = new HashSet(); public final List preReceiveScripts = new ArrayList(); public final List postReceiveScripts = new ArrayList(); @@ -45,24 +54,136 @@ public class TeamModel implements Serializable, Comparable { this.name = name; } + /** + * @use hasRepositoryPermission + * @param name + * @return + */ + @Deprecated + @Unused public boolean hasRepository(String name) { - return repositories.contains(name.toLowerCase()); + return hasRepositoryPermission(name); } + @Deprecated + @Unused public void addRepository(String name) { - repositories.add(name.toLowerCase()); + addRepositoryPermission(name); } + @Deprecated + @Unused public void addRepositories(Collection names) { - for (String name:names) { - repositories.add(name.toLowerCase()); - } - } + addRepositoryPermissions(names); + } + @Deprecated + @Unused public void removeRepository(String name) { - repositories.remove(name.toLowerCase()); + removeRepositoryPermission(name); + } + + /** + * Returns true if the team has any type of specified access permission for + * this repository. + * + * @param name + * @return true if team has a specified access permission for the repository + */ + public boolean hasRepositoryPermission(String name) { + String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); + return permissions.containsKey(repository) || repositories.contains(repository); } + /** + * Adds a repository permission to the team. + *

+ * Role may be formatted as: + *

    + *
  • myrepo.git (this is implicitly RW+) + *
  • RW+:myrepo.git + *
+ * @param role + */ + public void addRepositoryPermission(String role) { + AccessPermission permission = AccessPermission.permissionFromRole(role); + String repository = AccessPermission.repositoryFromRole(role).toLowerCase(); + repositories.add(repository); + permissions.put(repository, permission); + } + + public void addRepositoryPermissions(Collection roles) { + for (String role:roles) { + addRepositoryPermission(role); + } + } + + public AccessPermission removeRepositoryPermission(String name) { + String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); + repositories.remove(repository); + return permissions.remove(repository); + } + + public void setRepositoryPermission(String repository, AccessPermission permission) { + permissions.put(repository.toLowerCase(), permission); + repositories.add(repository.toLowerCase()); + } + + public AccessPermission getRepositoryPermission(RepositoryModel repository) { + AccessPermission permission = AccessPermission.NONE; + if (permissions.containsKey(repository.name.toLowerCase())) { + AccessPermission p = permissions.get(repository.name.toLowerCase()); + if (p != null) { + permission = p; + } + } + return permission; + } + + private boolean canAccess(RepositoryModel repository, AccessRestrictionType ifRestriction, AccessPermission requirePermission) { + if (repository.accessRestriction.atLeast(ifRestriction)) { + AccessPermission permission = getRepositoryPermission(repository); + return permission.atLeast(requirePermission); + } + return true; + } + + public boolean canView(RepositoryModel repository) { + return canAccess(repository, AccessRestrictionType.VIEW, AccessPermission.VIEW); + } + + public boolean canClone(RepositoryModel repository) { + return canAccess(repository, AccessRestrictionType.CLONE, AccessPermission.CLONE); + } + + public boolean canPush(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.PUSH); + } + + public boolean canCreateRef(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.CREATE); + } + + public boolean canDeleteRef(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.DELETE); + } + + public boolean canRewindRef(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.REWIND); + } + public boolean hasUser(String name) { return users.contains(name.toLowerCase()); } diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java index 94bd055d..ee730257 100644 --- a/src/com/gitblit/models/UserModel.java +++ b/src/com/gitblit/models/UserModel.java @@ -17,11 +17,15 @@ package com.gitblit.models; import java.io.Serializable; import java.security.Principal; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; +import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.Unused; import com.gitblit.utils.StringUtils; /** @@ -48,7 +52,10 @@ public class UserModel implements Principal, Serializable, Comparable public boolean canFork; public boolean canCreate; public boolean excludeFromFederation; + // retained for backwards-compatibility with RPC clients + @Deprecated public final Set repositories = new HashSet(); + public final Map permissions = new HashMap(); public final Set teams = new HashSet(); // non-persisted fields @@ -77,6 +84,8 @@ public class UserModel implements Principal, Serializable, Comparable || hasTeamAccess(repositoryName); } + @Deprecated + @Unused public boolean canAccessRepository(RepositoryModel repository) { boolean isOwner = !StringUtils.isEmpty(repository.owner) && repository.owner.equals(username); @@ -85,62 +94,170 @@ public class UserModel implements Principal, Serializable, Comparable || hasTeamAccess(repository.name) || allowAuthenticated; } + @Deprecated + @Unused public boolean hasTeamAccess(String repositoryName) { for (TeamModel team : teams) { - if (team.hasRepository(repositoryName)) { + if (team.hasRepositoryPermission(repositoryName)) { return true; } } return false; } - public boolean canViewRepository(RepositoryModel repository) { - if (canAdmin) { - return true; + @Deprecated + @Unused + public boolean hasRepository(String name) { + return hasRepositoryPermission(name); + } + + @Deprecated + @Unused + public void addRepository(String name) { + addRepositoryPermission(name); + } + + @Deprecated + @Unused + public void removeRepository(String name) { + removeRepositoryPermission(name); + } + + /** + * Returns true if the user has any type of specified access permission for + * this repository. + * + * @param name + * @return true if user has a specified access permission for the repository + */ + public boolean hasRepositoryPermission(String name) { + String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); + return permissions.containsKey(repository) || repositories.contains(repository); + } + + /** + * Adds a repository permission to the team. + *

+ * Role may be formatted as: + *

    + *
  • myrepo.git (this is implicitly RW+) + *
  • RW+:myrepo.git + *
+ * @param role + */ + public void addRepositoryPermission(String role) { + AccessPermission permission = AccessPermission.permissionFromRole(role); + String repository = AccessPermission.repositoryFromRole(role).toLowerCase(); + repositories.add(repository); + permissions.put(repository, permission); + } + + public AccessPermission removeRepositoryPermission(String name) { + String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); + repositories.remove(repository); + return permissions.remove(repository); + } + + public void setRepositoryPermission(String repository, AccessPermission permission) { + permissions.put(repository.toLowerCase(), permission); + } + + public AccessPermission getRepositoryPermission(RepositoryModel repository) { + if (canAdmin || repository.isOwner(username) || repository.isUsersPersonalRepository(username)) { + return AccessPermission.REWIND; + } + if (AuthorizationControl.AUTHENTICATED.equals(repository.authorizationControl) && isAuthenticated) { + // AUTHENTICATED is a shortcut for authorizing all logged-in users RW access + return AccessPermission.REWIND; } - if (repository.accessRestriction.atLeast(AccessRestrictionType.VIEW)) { - return canAccessRepository(repository); + + // determine best permission available based on user's personal permissions + // and the permissions of teams of which the user belongs + AccessPermission permission = AccessPermission.NONE; + if (permissions.containsKey(repository.name.toLowerCase())) { + AccessPermission p = permissions.get(repository.name.toLowerCase()); + if (p != null) { + permission = p; + } + } + + for (TeamModel team : teams) { + AccessPermission p = team.getRepositoryPermission(repository); + if (permission == null || p.exceeds(permission)) { + // use team permission + permission = p; + } + } + return permission; + } + + private boolean canAccess(RepositoryModel repository, AccessRestrictionType ifRestriction, AccessPermission requirePermission) { + if (repository.accessRestriction.atLeast(ifRestriction)) { + AccessPermission permission = getRepositoryPermission(repository); + return permission.atLeast(requirePermission); } return true; } - public boolean canForkRepository(RepositoryModel repository) { - if (canAdmin) { - return true; + public boolean canView(RepositoryModel repository) { + return canAccess(repository, AccessRestrictionType.VIEW, AccessPermission.VIEW); + } + + public boolean canClone(RepositoryModel repository) { + return canAccess(repository, AccessRestrictionType.CLONE, AccessPermission.CLONE); + } + + public boolean canPush(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.PUSH); + } + + public boolean canCreateRef(RepositoryModel repository) { + if (repository.isFrozen) { + return false; } - if (!canFork) { - // user has been prohibited from forking + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.CREATE); + } + + public boolean canDeleteRef(RepositoryModel repository) { + if (repository.isFrozen) { return false; } - if (!isAuthenticated) { - // unauthenticated user model + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.DELETE); + } + + public boolean canRewindRef(RepositoryModel repository) { + if (repository.isFrozen) { return false; } - if (("~" + username).equalsIgnoreCase(repository.projectPath)) { - // this repository is already a personal repository + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.REWIND); + } + + public boolean canFork(RepositoryModel repository) { + if (repository.isUsersPersonalRepository(username)) { + // can not fork your own repository return false; } + if (canAdmin || repository.isOwner(username)) { + return true; + } if (!repository.allowForks) { - // repository prohibits forks return false; } - if (repository.accessRestriction.atLeast(AccessRestrictionType.CLONE)) { - return canAccessRepository(repository); + if (!isAuthenticated || !canFork) { + return false; } - // repository is not clone-restricted - return true; - } - - public boolean hasRepository(String name) { - return repositories.contains(name.toLowerCase()); + return canClone(repository); } - - public void addRepository(String name) { - repositories.add(name.toLowerCase()); + + public boolean canDelete(RepositoryModel model) { + return canAdmin || model.isUsersPersonalRepository(username); } - - public void removeRepository(String name) { - repositories.remove(name.toLowerCase()); + + public boolean canEdit(RepositoryModel model) { + return canAdmin || model.isUsersPersonalRepository(username) || model.isOwner(username); } public boolean isTeamMember(String teamname) { diff --git a/src/com/gitblit/utils/JsonUtils.java b/src/com/gitblit/utils/JsonUtils.java index bc9a1e00..24f4ecb8 100644 --- a/src/com/gitblit/utils/JsonUtils.java +++ b/src/com/gitblit/utils/JsonUtils.java @@ -32,6 +32,7 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; +import com.gitblit.Constants.AccessPermission; import com.gitblit.GitBlitException.ForbiddenException; import com.gitblit.GitBlitException.NotAllowedException; import com.gitblit.GitBlitException.UnauthorizedException; @@ -266,6 +267,7 @@ public class JsonUtils { public static Gson gson(ExclusionStrategy... strategies) { GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(Date.class, new GmtDateTypeAdapter()); + builder.registerTypeAdapter(AccessPermission.class, new AccessPermissionTypeAdapter()); builder.setPrettyPrinting(); if (!ArrayUtils.isEmpty(strategies)) { builder.setExclusionStrategies(strategies); @@ -303,6 +305,24 @@ public class JsonUtils { } } } + + private static class AccessPermissionTypeAdapter implements JsonSerializer, JsonDeserializer { + + private AccessPermissionTypeAdapter() { + } + + @Override + public synchronized JsonElement serialize(AccessPermission permission, Type type, + JsonSerializationContext jsonSerializationContext) { + return new JsonPrimitive(permission.code); + } + + @Override + public synchronized AccessPermission deserialize(JsonElement jsonElement, Type type, + JsonDeserializationContext jsonDeserializationContext) { + return AccessPermission.fromCode(jsonElement.getAsString()); + } + } public static class ExcludeField implements ExclusionStrategy { diff --git a/src/com/gitblit/wicket/pages/BasePage.java b/src/com/gitblit/wicket/pages/BasePage.java index 00d9677f..cce323fd 100644 --- a/src/com/gitblit/wicket/pages/BasePage.java +++ b/src/com/gitblit/wicket/pages/BasePage.java @@ -297,7 +297,7 @@ public abstract class BasePage extends WebPage { for (ProjectModel projectModel : availableModels) { for (String repositoryName : projectModel.repositories) { for (TeamModel teamModel : teamModels) { - if (teamModel.hasRepository(repositoryName)) { + if (teamModel.hasRepositoryPermission(repositoryName)) { models.add(projectModel); } } diff --git a/src/com/gitblit/wicket/pages/ForkPage.java b/src/com/gitblit/wicket/pages/ForkPage.java index 082dab51..340bd823 100644 --- a/src/com/gitblit/wicket/pages/ForkPage.java +++ b/src/com/gitblit/wicket/pages/ForkPage.java @@ -40,7 +40,7 @@ public class ForkPage extends RepositoryPage { RepositoryModel repository = getRepositoryModel(); UserModel user = session.getUser(); - boolean canFork = user.canForkRepository(repository); + boolean canFork = user.canFork(repository); if (!canFork) { // redirect to the summary page if this repository is not empty diff --git a/src/com/gitblit/wicket/pages/ForksPage.java b/src/com/gitblit/wicket/pages/ForksPage.java index 2e67e2b7..6155f3ed 100644 --- a/src/com/gitblit/wicket/pages/ForksPage.java +++ b/src/com/gitblit/wicket/pages/ForksPage.java @@ -94,7 +94,7 @@ public class ForksPage extends RepositoryPage { if (user == null) { user = UserModel.ANONYMOUS; } - if (user.canViewRepository(repository)) { + if (user.canView(repository)) { if (pageRepository.equals(repository)) { // do not link to self item.add(new Label("aFork", StringUtils.stripDotGit(repo))); diff --git a/src/com/gitblit/wicket/pages/RepositoryPage.java b/src/com/gitblit/wicket/pages/RepositoryPage.java index 2afc2c4d..9048eba3 100644 --- a/src/com/gitblit/wicket/pages/RepositoryPage.java +++ b/src/com/gitblit/wicket/pages/RepositoryPage.java @@ -209,7 +209,7 @@ public abstract class RepositoryPage extends BasePage { if (origin == null) { // no origin repository add(new Label("originRepository").setVisible(false)); - } else if (!user.canViewRepository(origin)) { + } else if (!user.canView(origin)) { // show origin repository without link Fragment forkFrag = new Fragment("originRepository", "originFragment", this); forkFrag.add(new Label("originRepository", StringUtils.stripDotGit(model.originRepository))); @@ -242,7 +242,7 @@ public abstract class RepositoryPage extends BasePage { } else { String fork = GitBlit.self().getFork(user.username, model.name); boolean hasFork = fork != null; - boolean canFork = user.canForkRepository(model); + boolean canFork = user.canFork(model); if (hasFork || !canFork) { // user not allowed to fork or fork already exists or repo forbids forking diff --git a/src/com/gitblit/wicket/pages/RootPage.java b/src/com/gitblit/wicket/pages/RootPage.java index 1e6f130c..adcd7b16 100644 --- a/src/com/gitblit/wicket/pages/RootPage.java +++ b/src/com/gitblit/wicket/pages/RootPage.java @@ -418,7 +418,7 @@ public abstract class RootPage extends BasePage { // brute-force our way through finding the matching models for (RepositoryModel repositoryModel : availableModels) { for (TeamModel teamModel : teamModels) { - if (teamModel.hasRepository(repositoryModel.name)) { + if (teamModel.hasRepositoryPermission(repositoryModel.name)) { models.add(repositoryModel); } } diff --git a/tests/com/gitblit/tests/FederationTests.java b/tests/com/gitblit/tests/FederationTests.java index 2c4ffdc9..c8f686ad 100644 --- a/tests/com/gitblit/tests/FederationTests.java +++ b/tests/com/gitblit/tests/FederationTests.java @@ -136,7 +136,7 @@ public class FederationTests { TeamModel team = new TeamModel("testteam"); team.addUser("test"); - team.addRepository("helloworld.git"); + team.addRepositoryPermission("helloworld.git"); assertTrue(RpcUtils.createTeam(team, url, account, password.toCharArray())); users = FederationUtils.getUsers(getRegistration()); diff --git a/tests/com/gitblit/tests/GitBlitSuite.java b/tests/com/gitblit/tests/GitBlitSuite.java index 07c5e08e..22bcf137 100644 --- a/tests/com/gitblit/tests/GitBlitSuite.java +++ b/tests/com/gitblit/tests/GitBlitSuite.java @@ -49,7 +49,7 @@ import com.gitblit.utils.JGitUtils; @RunWith(Suite.class) @SuiteClasses({ ArrayUtilsTest.class, FileUtilsTest.class, TimeUtilsTest.class, StringUtilsTest.class, Base64Test.class, JsonUtilsTest.class, ByteFormatTest.class, - ObjectCacheTest.class, UserServiceTest.class, LdapUserServiceTest.class, + ObjectCacheTest.class, PermissionsTest.class, UserServiceTest.class, LdapUserServiceTest.class, MarkdownUtilsTest.class, JGitUtilsTest.class, SyndicationUtilsTest.class, DiffUtilsTest.class, MetricUtilsTest.class, TicgitUtilsTest.class, GitBlitTest.class, FederationTests.class, RpcTests.class, GitServletTest.class, diff --git a/tests/com/gitblit/tests/GitBlitTest.java b/tests/com/gitblit/tests/GitBlitTest.java index 418f9384..a188f180 100644 --- a/tests/com/gitblit/tests/GitBlitTest.java +++ b/tests/com/gitblit/tests/GitBlitTest.java @@ -52,20 +52,21 @@ public class GitBlitTest { List users = GitBlit.self().getAllUsernames(); assertTrue("No users found!", users.size() > 0); assertTrue("Admin not found", users.contains("admin")); - UserModel model = GitBlit.self().getUserModel("admin"); - assertEquals("admin", model.toString()); - assertTrue("Admin missing #admin role!", model.canAdmin); - model.canAdmin = false; - assertFalse("Admin should not have #admin!", model.canAdmin); + UserModel user = GitBlit.self().getUserModel("admin"); + assertEquals("admin", user.toString()); + assertTrue("Admin missing #admin role!", user.canAdmin); + user.canAdmin = false; + assertFalse("Admin should not have #admin!", user.canAdmin); String repository = GitBlitSuite.getHelloworldRepository().getDirectory().getName(); RepositoryModel repositoryModel = GitBlit.self().getRepositoryModel(repository); + repositoryModel.accessRestriction = AccessRestrictionType.VIEW; assertFalse("Admin can still access repository!", - model.canAccessRepository(repositoryModel)); - model.addRepository(repository); - assertTrue("Admin can't access repository!", model.canAccessRepository(repositoryModel)); - assertEquals(GitBlit.self().getRepositoryModel(model, "pretend"), null); - assertNotNull(GitBlit.self().getRepositoryModel(model, repository)); - assertTrue(GitBlit.self().getRepositoryModels(model).size() > 0); + user.canView(repositoryModel)); + user.addRepositoryPermission(repository); + assertTrue("Admin can't access repository!", user.canView(repositoryModel)); + assertEquals(GitBlit.self().getRepositoryModel(user, "pretend"), null); + assertNotNull(GitBlit.self().getRepositoryModel(user, repository)); + assertTrue(GitBlit.self().getRepositoryModels(user).size() > 0); } @Test diff --git a/tests/com/gitblit/tests/GitServletTest.java b/tests/com/gitblit/tests/GitServletTest.java index bdbb2a5a..09e0e5ad 100644 --- a/tests/com/gitblit/tests/GitServletTest.java +++ b/tests/com/gitblit/tests/GitServletTest.java @@ -13,18 +13,28 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jgit.api.CloneCommand; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.ResetCommand.ResetType; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.PushResult; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteRefUpdate; +import org.eclipse.jgit.transport.RemoteRefUpdate.Status; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.eclipse.jgit.util.FileUtils; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; import com.gitblit.GitBlit; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; +import com.gitblit.utils.JGitUtils; public class GitServletTest { @@ -233,6 +243,213 @@ public class GitServletTest { } close(git); } + + @Test + public void testBlockClone() throws Exception { + testRefChange(AccessPermission.VIEW, null, null, null); + } + + @Test + public void testBlockPush() throws Exception { + testRefChange(AccessPermission.CLONE, null, null, null); + } + + @Test + public void testBlockBranchCreation() throws Exception { + testRefChange(AccessPermission.PUSH, Status.REJECTED_OTHER_REASON, null, null); + } + + @Test + public void testBlockBranchDeletion() throws Exception { + testRefChange(AccessPermission.CREATE, Status.OK, Status.REJECTED_OTHER_REASON, null); + } + + @Test + public void testBlockBranchRewind() throws Exception { + testRefChange(AccessPermission.DELETE, Status.OK, Status.OK, Status.REJECTED_OTHER_REASON); + } + + @Test + public void testBranchRewind() throws Exception { + testRefChange(AccessPermission.REWIND, Status.OK, Status.OK, Status.OK); + } + + private void testRefChange(AccessPermission permission, Status expectedCreate, Status expectedDelete, Status expectedRewind) throws Exception { + + UserModel user = new UserModel("james"); + user.password = "james"; + + if (GitBlit.self().getUserModel(user.username) != null) { + GitBlit.self().deleteUser(user.username); + } + + CredentialsProvider cp = new UsernamePasswordCredentialsProvider(user.username, user.password); + + // fork from original to a temporary bare repo + File refChecks = new File(GitBlitSuite.REPOSITORIES, "refchecks/ticgit.git"); + if (refChecks.exists()) { + FileUtils.delete(refChecks, FileUtils.RECURSIVE); + } + CloneCommand clone = Git.cloneRepository(); + clone.setURI(MessageFormat.format("{0}/git/ticgit.git", url)); + clone.setDirectory(refChecks); + clone.setBare(true); + clone.setCloneAllBranches(true); + clone.setCredentialsProvider(cp); + close(clone.call()); + + // elevate repository to clone permission + RepositoryModel model = GitBlit.self().getRepositoryModel("refchecks/ticgit.git"); + switch (permission) { + case VIEW: + model.accessRestriction = AccessRestrictionType.CLONE; + break; + case CLONE: + model.accessRestriction = AccessRestrictionType.CLONE; + break; + default: + model.accessRestriction = AccessRestrictionType.PUSH; + } + model.authorizationControl = AuthorizationControl.NAMED; + + // grant user specified + user.setRepositoryPermission(model.name, permission); + + GitBlit.self().updateUserModel(user.username, user, true); + GitBlit.self().updateRepositoryModel(model.name, model, false); + + // clone temp bare repo to working copy + File local = new File(GitBlitSuite.REPOSITORIES, "refchecks/ticgit-wc"); + if (local.exists()) { + FileUtils.delete(local, FileUtils.RECURSIVE); + } + clone = Git.cloneRepository(); + clone.setURI(MessageFormat.format("{0}/git/{1}", url, model.name)); + clone.setDirectory(local); + clone.setBare(false); + clone.setCloneAllBranches(true); + clone.setCredentialsProvider(cp); + + try { + close(clone.call()); + } catch (GitAPIException e) { + if (permission.atLeast(AccessPermission.CLONE)) { + throw e; + } else { + // user does not have clone permission + assertTrue(e.getMessage(), e.getMessage().contains("not permitted")); + return; + } + } + + Git git = Git.open(local); + + // commit a file and push it + File file = new File(local, "PUSHCHK"); + OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET); + BufferedWriter w = new BufferedWriter(os); + w.write("// " + new Date().toString() + "\n"); + w.close(); + git.add().addFilepattern(file.getName()).call(); + git.commit().setMessage("push test").call(); + Iterable results = null; + try { + results = git.push().setCredentialsProvider(cp).setRemote("origin").call(); + } catch (GitAPIException e) { + if (permission.atLeast(AccessPermission.PUSH)) { + throw e; + } else { + // user does not have push permission + assertTrue(e.getMessage(), e.getMessage().contains("not permitted")); + close(git); + return; + } + } + + for (PushResult result : results) { + RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/master"); + Status status = ref.getStatus(); + if (permission.atLeast(AccessPermission.PUSH)) { + assertTrue("User failed to push commit?! " + status.name(), Status.OK.equals(status)); + } else { + assertTrue("User was able to push commit! " + status.name(), Status.REJECTED_OTHER_REASON.equals(status)); + close(git); + // skip delete test + return; + } + } + + // create a local branch and push the new branch back to the origin + git.branchCreate().setName("protectme").call(); + RefSpec refSpec = new RefSpec("refs/heads/protectme:refs/heads/protectme"); + results = git.push().setCredentialsProvider(cp).setRefSpecs(refSpec).setRemote("origin").call(); + for (PushResult result : results) { + RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/protectme"); + Status status = ref.getStatus(); + if (Status.OK.equals(expectedCreate)) { + assertTrue("User failed to push creation?! " + status.name(), status.equals(expectedCreate)); + } else { + assertTrue("User was able to push ref creation! " + status.name(), status.equals(expectedCreate)); + close(git); + // skip delete test + return; + } + } + + // delete the branch locally + git.branchDelete().setBranchNames("protectme").call(); + + // push a delete ref command + refSpec = new RefSpec(":refs/heads/protectme"); + results = git.push().setCredentialsProvider(cp).setRefSpecs(refSpec).setRemote("origin").call(); + for (PushResult result : results) { + RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/protectme"); + Status status = ref.getStatus(); + if (Status.OK.equals(expectedDelete)) { + assertTrue("User failed to push ref deletion?! " + status.name(), status.equals(Status.OK)); + } else { + assertTrue("User was able to push ref deletion?! " + status.name(), status.equals(expectedDelete)); + close(git); + // skip rewind test + return; + } + } + + // rewind master by two commits + git.reset().setRef("HEAD~2").setMode(ResetType.HARD).call(); + + // commit a change on this detached HEAD + file = new File(local, "REWINDCHK"); + os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET); + w = new BufferedWriter(os); + w.write("// " + new Date().toString() + "\n"); + w.close(); + git.add().addFilepattern(file.getName()).call(); + RevCommit commit = git.commit().setMessage("rewind master and new commit").call(); + + // Reset master to our new commit now we our local branch tip is no longer + // upstream of the remote branch tip. It is an alternate tip of the branch. + JGitUtils.setBranchRef(git.getRepository(), "refs/heads/master", commit.getName()); + + // Try pushing our new tip to the origin. + // This requires the server to "rewind" it's master branch and update it + // to point to our alternate tip. This leaves the original master tip + // unreferenced. + results = git.push().setCredentialsProvider(cp).setRemote("origin").setForce(true).call(); + for (PushResult result : results) { + RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/master"); + Status status = ref.getStatus(); + if (Status.OK.equals(expectedRewind)) { + assertTrue("User failed to rewind master?! " + status.name(), status.equals(expectedRewind)); + } else { + assertTrue("User was able to rewind master?! " + status.name(), status.equals(expectedRewind)); + } + } + close(git); + + GitBlit.self().deleteUser(user.username); + } + private void close(Git git) { // really close the repository diff --git a/tests/com/gitblit/tests/JGitUtilsTest.java b/tests/com/gitblit/tests/JGitUtilsTest.java index f4870461..7e4d6309 100644 --- a/tests/com/gitblit/tests/JGitUtilsTest.java +++ b/tests/com/gitblit/tests/JGitUtilsTest.java @@ -35,6 +35,7 @@ import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryCache; import org.eclipse.jgit.lib.RepositoryCache.FileKey; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevTree; @@ -141,7 +142,8 @@ public class JGitUtilsTest { assertEquals(folder.lastModified(), JGitUtils.getLastChange(repository).getTime()); assertNull(JGitUtils.getCommit(repository, null)); repository.close(); - assertTrue(GitBlit.self().deleteRepository(repositoryName)); + RepositoryCache.close(repository); + FileUtils.delete(repository.getDirectory(), FileUtils.RECURSIVE); } } diff --git a/tests/com/gitblit/tests/PermissionsTest.java b/tests/com/gitblit/tests/PermissionsTest.java new file mode 100644 index 00000000..cb9925e8 --- /dev/null +++ b/tests/com/gitblit/tests/PermissionsTest.java @@ -0,0 +1,2391 @@ +/* + * Copyright 2012 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.tests; + +import java.util.Date; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.gitblit.Constants.AccessPermission; +import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.TeamModel; +import com.gitblit.models.UserModel; + +/** + * Comprehensive, brute-force test of all permutations of discrete permissions. + * + * @author James Moger + * + */ +public class PermissionsTest extends Assert { + + /** + * Admin access rights/permissions + */ + @Test + public void testAdmin() throws Exception { + UserModel user = new UserModel("admin"); + user.canAdmin = true; + + for (AccessRestrictionType ar : AccessRestrictionType.values()) { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = ar; + + assertTrue("admin CAN NOT view!", user.canView(repository)); + assertTrue("admin CAN NOT clone!", user.canClone(repository)); + assertTrue("admin CAN NOT push!", user.canPush(repository)); + + assertTrue("admin CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("admin CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("admin CAN NOT rewind ref!", user.canRewindRef(repository)); + + assertTrue("admin CAN NOT fork!", user.canFork(repository)); + + assertTrue("admin CAN NOT delete!", user.canDelete(repository)); + assertTrue("admin CAN NOT edit!", user.canEdit(repository)); + } + } + + /** + * Anonymous access rights/permissions + */ + @Test + public void testAnonymous_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + UserModel user = UserModel.ANONYMOUS; + + // all permissions, except fork + assertTrue("anonymous CAN NOT view!", user.canView(repository)); + assertTrue("anonymous CAN NOT clone!", user.canClone(repository)); + assertTrue("anonymous CAN NOT push!", user.canPush(repository)); + + assertTrue("anonymous CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("anonymous CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("anonymous CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + assertFalse("anonymous CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("anonymous CAN fork!", user.canFork(repository)); + + assertFalse("anonymous CAN delete!", user.canDelete(repository)); + assertFalse("anonymous CAN edit!", user.canEdit(repository)); + } + + @Test + public void testAnonymous_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + UserModel user = UserModel.ANONYMOUS; + + assertTrue("anonymous CAN NOT view!", user.canView(repository)); + assertTrue("anonymous CAN NOT clone!", user.canClone(repository)); + assertFalse("anonymous CAN push!", user.canPush(repository)); + + assertFalse("anonymous CAN create ref!", user.canCreateRef(repository)); + assertFalse("anonymous CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("anonymous CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + assertFalse("anonymous CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("anonymous CAN fork!", user.canFork(repository)); + } + + @Test + public void testAnonymous_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + UserModel user = UserModel.ANONYMOUS; + + assertTrue("anonymous CAN NOT view!", user.canView(repository)); + assertFalse("anonymous CAN clone!", user.canClone(repository)); + assertFalse("anonymous CAN push!", user.canPush(repository)); + + assertFalse("anonymous CAN create ref!", user.canCreateRef(repository)); + assertFalse("anonymous CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("anonymous CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + assertFalse("anonymous CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("anonymous CAN fork!", user.canFork(repository)); + } + + @Test + public void testAnonymous_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = UserModel.ANONYMOUS; + + assertFalse("anonymous CAN view!", user.canView(repository)); + assertFalse("anonymous CAN clone!", user.canClone(repository)); + assertFalse("anonymous CAN push!", user.canPush(repository)); + + assertFalse("anonymous CAN create ref!", user.canCreateRef(repository)); + assertFalse("anonymous CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("anonymous CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + assertFalse("anonymous CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("anonymous CAN fork!", user.canFork(repository)); + } + + /** + * Authenticated access rights/permissions + */ + @Test + public void testAuthenticated_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.AUTHENTICATED; + repository.accessRestriction = AccessRestrictionType.NONE; + + UserModel user = new UserModel("test"); + + // all permissions, except fork + assertTrue("authenticated CAN NOT view!", user.canView(repository)); + assertTrue("authenticated CAN NOT clone!", user.canClone(repository)); + assertTrue("authenticated CAN NOT push!", user.canPush(repository)); + + assertTrue("authenticated CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("authenticated CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("authenticated CAN NOT rewind ref!", user.canRewindRef(repository)); + + user.canFork = false; + repository.allowForks = false; + assertFalse("authenticated CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("authenticated CAN fork!", user.canFork(repository)); + user.canFork = true; + assertTrue("authenticated CAN NOT fork!", user.canFork(repository)); + + assertFalse("authenticated CAN delete!", user.canDelete(repository)); + assertFalse("authenticated CAN edit!", user.canEdit(repository)); + } + + @Test + public void testAuthenticated_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.AUTHENTICATED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + UserModel user = new UserModel("test"); + + assertTrue("authenticated CAN NOT view!", user.canView(repository)); + assertTrue("authenticated CAN NOT clone!", user.canClone(repository)); + assertTrue("authenticated CAN NOT push!", user.canPush(repository)); + + assertTrue("authenticated CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("authenticated CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("authenticated CAN NOT rewind ref!", user.canRewindRef(repository)); + + user.canFork = false; + repository.allowForks = false; + assertFalse("authenticated CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("authenticated CAN fork!", user.canFork(repository)); + user.canFork = true; + assertTrue("authenticated CAN NOT fork!", user.canFork(repository)); + } + + @Test + public void testAuthenticated_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.AUTHENTICATED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + UserModel user = new UserModel("test"); + + assertTrue("authenticated CAN NOT view!", user.canView(repository)); + assertTrue("authenticated CAN NOT clone!", user.canClone(repository)); + assertTrue("authenticated CAN NOT push!", user.canPush(repository)); + + assertTrue("authenticated CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("authenticated CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("authenticated CAN NOT rewind ref!", user.canRewindRef(repository)); + + user.canFork = false; + repository.allowForks = false; + assertFalse("authenticated CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("authenticated CAN fork!", user.canFork(repository)); + user.canFork = true; + assertTrue("authenticated CAN NOT fork!", user.canFork(repository)); + } + + @Test + public void testAuthenticated_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.AUTHENTICATED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + + assertTrue("authenticated CAN NOT view!", user.canView(repository)); + assertTrue("authenticated CAN NOT clone!", user.canClone(repository)); + assertTrue("authenticated CAN NOT push!", user.canPush(repository)); + + assertTrue("authenticated CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("authenticated CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("authenticated CAN NOT rewind ref!", user.canRewindRef(repository)); + + user.canFork = false; + repository.allowForks = false; + assertFalse("authenticated CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("authenticated CAN fork!", user.canFork(repository)); + user.canFork = true; + assertTrue("authenticated CAN NOT fork!", user.canFork(repository)); + } + + /** + * NONE_NONE = NO access restriction, NO access permission + */ + @Test + public void testNamed_NONE_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + UserModel user = new UserModel("test"); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("named CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + + assertFalse("named CAN delete!", user.canDelete(repository)); + assertFalse("named CAN edit!", user.canEdit(repository)); + } + + /** + * PUSH_NONE = PUSH access restriction, NO access permission + */ + @Test + public void testNamed_PUSH_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + UserModel user = new UserModel("test"); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertFalse("named CAN push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * CLONE_NONE = CLONE access restriction, NO access permission + */ + @Test + public void testNamed_CLONE_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + UserModel user = new UserModel("test"); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertFalse("named CAN clone!", user.canClone(repository)); + assertFalse("named CAN push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * VIEW_NONE = VIEW access restriction, NO access permission + */ + @Test + public void testNamed_VIEW_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + + assertFalse("named CAN view!", user.canView(repository)); + assertFalse("named CAN clone!", user.canClone(repository)); + assertFalse("named CAN push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("named CAN NOT fork!", user.canFork(repository)); + } + + + /** + * NONE_VIEW = NO access restriction, VIEW access permission. + * (not useful scenario) + */ + @Test + public void testNamed_NONE_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.VIEW); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("named CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * PUSH_VIEW = PUSH access restriction, VIEW access permission + */ + @Test + public void testNamed_PUSH_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.VIEW); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertFalse("named CAN push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * CLONE_VIEW = CLONE access restriction, VIEW access permission + */ + @Test + public void testNamed_CLONE_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.VIEW); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertFalse("named CAN clone!", user.canClone(repository)); + assertFalse("named CAN push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * VIEW_VIEW = VIEW access restriction, VIEW access permission + */ + @Test + public void testNamed_VIEW_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.VIEW); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertFalse("named CAN clone!", user.canClone(repository)); + assertFalse("named CAN push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertFalse("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * NONE_CLONE = NO access restriction, CLONE access permission. + * (not useful scenario) + */ + @Test + public void testNamed_NONE_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.CLONE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("named CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * PUSH_CLONE = PUSH access restriction, CLONE access permission + */ + @Test + public void testNamed_PUSH_READ() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.CLONE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertFalse("named CAN push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * CLONE_CLONE = CLONE access restriction, CLONE access permission + */ + @Test + public void testNamed_CLONE_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.CLONE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertFalse("named CAN push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * VIEW_CLONE = VIEW access restriction, CLONE access permission + */ + @Test + public void testNamed_VIEW_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.CLONE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertFalse("named CAN push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * NONE_PUSH = NO access restriction, PUSH access permission. + * (not useful scenario) + */ + @Test + public void testNamed_NONE_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.PUSH); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("named CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * PUSH_PUSH = PUSH access restriction, PUSH access permission + */ + @Test + public void testNamed_PUSH_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.PUSH); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * CLONE_PUSH = CLONE access restriction, PUSH access permission + */ + @Test + public void testNamed_CLONE_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.PUSH); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete red!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * VIEW_PUSH = VIEW access restriction, PUSH access permission + */ + @Test + public void testNamed_VIEW_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.PUSH); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN not push!", user.canPush(repository)); + + assertFalse("named CAN create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * NONE_CREATE = NO access restriction, CREATE access permission. + * (not useful scenario) + */ + @Test + public void testNamed_NONE_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.CREATE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("named CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * PUSH_CREATE = PUSH access restriction, CREATE access permission + */ + @Test + public void testNamed_PUSH_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.CREATE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * CLONE_CREATE = CLONE access restriction, CREATE access permission + */ + @Test + public void testNamed_CLONE_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.CREATE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete red!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * VIEW_CREATE = VIEW access restriction, CREATE access permission + */ + @Test + public void testNamed_VIEW_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.CREATE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN not push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertFalse("named CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * NONE_DELETE = NO access restriction, DELETE access permission. + * (not useful scenario) + */ + @Test + public void testNamed_NONE_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.DELETE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("named CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * PUSH_DELETE = PUSH access restriction, DELETE access permission + */ + @Test + public void testNamed_PUSH_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.DELETE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * CLONE_DELETE = CLONE access restriction, DELETE access permission + */ + @Test + public void testNamed_CLONE_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.DELETE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete red!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * VIEW_DELETE = VIEW access restriction, DELETE access permission + */ + @Test + public void testNamed_VIEW_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.DELETE); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN not push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertFalse("named CAN rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * NONE_REWIND = NO access restriction, REWIND access permission. + * (not useful scenario) + */ + @Test + public void testNamed_NONE_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.REWIND); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("named CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * PUSH_REWIND = PUSH access restriction, REWIND access permission + */ + @Test + public void testNamed_PUSH_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.REWIND); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("named CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * CLONE_REWIND = CLONE access restriction, REWIND access permission + */ + @Test + public void testNamed_CLONE_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.REWIND); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("named CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * VIEW_REWIND = VIEW access restriction, REWIND access permission + */ + @Test + public void testNamed_VIEW_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + user.setRepositoryPermission(repository.name, AccessPermission.REWIND); + + assertTrue("named CAN NOT view!", user.canView(repository)); + assertTrue("named CAN NOT clone!", user.canClone(repository)); + assertTrue("named CAN NOT push!", user.canPush(repository)); + + assertTrue("named CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("named CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("named CAN NOT rewind ref!", user.canRewindRef(repository)); + + repository.allowForks = false; + user.canFork = false; + assertFalse("named CAN fork!", user.canFork(repository)); + user.canFork = true; + assertFalse("named CAN fork!", user.canFork(repository)); + repository.allowForks = true; + assertTrue("named CAN NOT fork!", user.canFork(repository)); + } + + /** + * NONE_NONE = NO access restriction, NO access permission + */ + @Test + public void testTeam_NONE_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertTrue("team CAN NOT rewind ref!", team.canRewindRef(repository)); + } + + /** + * PUSH_NONE = PUSH access restriction, NO access permission + */ + @Test + public void testTeam_PUSH_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertFalse("team CAN push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * CLONE_NONE = CLONE access restriction, NO access permission + */ + @Test + public void testTeam_CLONE_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertFalse("team CAN clone!", team.canClone(repository)); + assertFalse("team CAN push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * VIEW_NONE = VIEW access restriction, NO access permission + */ + @Test + public void testTeam_VIEW_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + + assertFalse("team CAN view!", team.canView(repository)); + assertFalse("team CAN clone!", team.canClone(repository)); + assertFalse("team CAN push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * NONE_PUSH = NO access restriction, PUSH access permission + * (not useful scenario) + */ + @Test + public void testTeam_NONE_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.PUSH); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertTrue("team CAN NOT rewind ref!", team.canRewindRef(repository)); + } + + /** + * PUSH_PUSH = PUSH access restriction, PUSH access permission + */ + @Test + public void testTeam_PUSH_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.PUSH); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * CLONE_PUSH = CLONE access restriction, PUSH access permission + */ + @Test + public void testTeam_CLONE_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.PUSH); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * VIEW_PUSH = VIEW access restriction, PUSH access permission + */ + @Test + public void testTeam_VIEW_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.PUSH); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * NONE_CREATE = NO access restriction, CREATE access permission + * (not useful scenario) + */ + @Test + public void testTeam_NONE_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CREATE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertTrue("team CAN NOT rewind ref!", team.canRewindRef(repository)); + } + + /** + * PUSH_CREATE = PUSH access restriction, CREATE access permission + */ + @Test + public void testTeam_PUSH_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CREATE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * CLONE_CREATE = CLONE access restriction, CREATE access permission + */ + @Test + public void testTeam_CLONE_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CREATE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * VIEW_CREATE = VIEW access restriction, CREATE access permission + */ + @Test + public void testTeam_VIEW_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CREATE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * NONE_DELETE = NO access restriction, DELETE access permission + * (not useful scenario) + */ + @Test + public void testTeam_NONE_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.DELETE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertTrue("team CAN NOT rewind ref!", team.canRewindRef(repository)); + } + + /** + * PUSH_DELETE = PUSH access restriction, DELETE access permission + */ + @Test + public void testTeam_PUSH_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.DELETE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * CLONE_DELETE = CLONE access restriction, DELETE access permission + */ + @Test + public void testTeam_CLONE_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.DELETE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * VIEW_DELETE = VIEW access restriction, DELETE access permission + */ + @Test + public void testTeam_VIEW_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.DELETE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * NONE_REWIND = NO access restriction, REWIND access permission + * (not useful scenario) + */ + @Test + public void testTeam_NONE_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.REWIND); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertTrue("team CAN NOT rewind ref!", team.canRewindRef(repository)); + } + + /** + * PUSH_REWIND = PUSH access restriction, REWIND access permission + */ + @Test + public void testTeam_PUSH_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.REWIND); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertTrue("team CAN NOT rewind ref!", team.canRewindRef(repository)); + } + + /** + * CLONE_REWIND = CLONE access restriction, REWIND access permission + */ + @Test + public void testTeam_CLONE_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.REWIND); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertTrue("team CAN NOT rewind ref!", team.canRewindRef(repository)); + } + + /** + * VIEW_REWIND = VIEW access restriction, REWIND access permission + */ + @Test + public void testTeam_VIEW_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.REWIND); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertTrue("team CAN NOT rewind ref!", team.canRewindRef(repository)); + } + + /** + * NONE_CLONE = NO access restriction, CLONE access permission + * (not useful scenario) + */ + @Test + public void testTeam_NONE_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CLONE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertTrue("team CAN NOT rewind ref!", team.canRewindRef(repository)); + } + + /** + * PUSH_CLONE = PUSH access restriction, CLONE access permission + */ + @Test + public void testTeam_PUSH_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CLONE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertFalse("team CAN push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * CLONE_CLONE = CLONE access restriction, CLONE access permission + */ + @Test + public void testTeam_CLONE_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CLONE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertFalse("team CAN push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * VIEW_CLONE = VIEW access restriction, CLONE access permission + */ + @Test + public void testTeam_VIEW_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CLONE); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertFalse("team CAN push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * NONE_VIEW = NO access restriction, VIEW access permission + * (not useful scenario) + */ + @Test + public void testTeam_NONE_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.VIEW); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertTrue("team CAN NOT push!", team.canPush(repository)); + + assertTrue("team CAN NOT create ref!", team.canCreateRef(repository)); + assertTrue("team CAN NOT delete ref!", team.canDeleteRef(repository)); + assertTrue("team CAN NOT rewind ref!", team.canRewindRef(repository)); + } + + /** + * PUSH_VIEW = PUSH access restriction, VIEW access permission + */ + @Test + public void testTeam_PUSH_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.VIEW); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertTrue("team CAN NOT clone!", team.canClone(repository)); + assertFalse("team CAN push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * CLONE_VIEW = CLONE access restriction, VIEW access permission + */ + @Test + public void testTeam_CLONE_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.VIEW); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertFalse("team CAN clone!", team.canClone(repository)); + assertFalse("team CAN push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * VIEW_VIEW = VIEW access restriction, VIEW access permission + */ + @Test + public void testTeam_VIEW_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.VIEW); + + assertTrue("team CAN NOT view!", team.canView(repository)); + assertFalse("team CAN clone!", team.canClone(repository)); + assertFalse("team CAN push!", team.canPush(repository)); + + assertFalse("team CAN create ref!", team.canCreateRef(repository)); + assertFalse("team CAN delete ref!", team.canDeleteRef(repository)); + assertFalse("team CAN rewind ref!", team.canRewindRef(repository)); + } + + /** + * NONE_NONE = NO access restriction, NO access permission + */ + @Test + public void testTeamMember_NONE_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("team member CAN NOT rewind ref!", user.canRewindRef(repository)); + } + + /** + * PUSH_NONE = PUSH access restriction, NO access permission + */ + @Test + public void testTeamMember_PUSH_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertFalse("team member CAN push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * CLONE_NONE = CLONE access restriction, NO access permission + */ + @Test + public void testTeamMember_CLONE_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertFalse("team member CAN clone!", user.canClone(repository)); + assertFalse("team member CAN push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * VIEW_NONE = VIEW access restriction, NO access permission + */ + @Test + public void testTeamMember_VIEW_NONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertFalse("team member CAN view!", user.canView(repository)); + assertFalse("team member CAN clone!", user.canClone(repository)); + assertFalse("team member CAN push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * NONE_PUSH = NO access restriction, PUSH access permission + * (not useful scenario) + */ + @Test + public void testTeamMember_NONE_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.PUSH); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("team member CAN NOT rewind ref!", user.canRewindRef(repository)); + } + + /** + * PUSH_PUSH = PUSH access restriction, PUSH access permission + */ + @Test + public void testTeamMember_PUSH_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.PUSH); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * CLONE_PUSH = CLONE access restriction, PUSH access permission + */ + @Test + public void testTeamMember_CLONE_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.PUSH); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * VIEW_PUSH = VIEW access restriction, PUSH access permission + */ + @Test + public void testTeamMember_VIEW_PUSH() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.PUSH); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * NONE_CREATE = NO access restriction, CREATE access permission + * (not useful scenario) + */ + @Test + public void testTeamMember_NONE_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CREATE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("team member CAN NOT rewind ref!", user.canRewindRef(repository)); + } + + /** + * PUSH_CREATE = PUSH access restriction, CREATE access permission + */ + @Test + public void testTeamMember_PUSH_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CREATE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * CLONE_CREATE = CLONE access restriction, CREATE access permission + */ + @Test + public void testTeamMember_CLONE_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CREATE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * VIEW_CREATE = VIEW access restriction, CREATE access permission + */ + @Test + public void testTeamMember_VIEW_CREATE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CREATE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * NONE_DELETE = NO access restriction, DELETE access permission + * (not useful scenario) + */ + @Test + public void testTeamMember_NONE_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.DELETE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("team member CAN NOT rewind ref!", user.canRewindRef(repository)); + } + + /** + * PUSH_DELETE = PUSH access restriction, DELETE access permission + */ + @Test + public void testTeamMember_PUSH_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.DELETE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * CLONE_DELETE = CLONE access restriction, DELETE access permission + */ + @Test + public void testTeamMember_CLONE_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.DELETE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * VIEW_DELETE = VIEW access restriction, DELETE access permission + */ + @Test + public void testTeamMember_VIEW_DELETE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.DELETE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * NONE_REWIND = NO access restriction, REWIND access permission + * (not useful scenario) + */ + @Test + public void testTeamMember_NONE_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.REWIND); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("team member CAN NOT rewind ref!", user.canRewindRef(repository)); + } + + /** + * PUSH_REWIND = PUSH access restriction, REWIND access permission + */ + @Test + public void testTeamMember_PUSH_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.REWIND); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("team member CAN NOT rewind ref!", user.canRewindRef(repository)); + } + + /** + * CLONE_REWIND = CLONE access restriction, REWIND access permission + */ + @Test + public void testTeamMember_CLONE_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.REWIND); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("team member CAN NOT rewind ref!", user.canRewindRef(repository)); + } + + /** + * VIEW_REWIND = VIEW access restriction, REWIND access permission + */ + @Test + public void testTeamMember_VIEW_REWIND() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.REWIND); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("team member CAN NOT rewind ref!", user.canRewindRef(repository)); + } + + /** + * NONE_CLONE = NO access restriction, CLONE access permission + * (not useful scenario) + */ + @Test + public void testTeamMember_NONE_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CLONE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("team member CAN NOT rewind ref!", user.canRewindRef(repository)); + } + + /** + * PUSH_CLONE = PUSH access restriction, CLONE access permission + */ + @Test + public void testTeamMember_PUSH_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CLONE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertFalse("team member CAN push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * CLONE_CLONE = CLONE access restriction, CLONE access permission + */ + @Test + public void testTeamMember_CLONE_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CLONE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertFalse("team member CAN push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * VIEW_CLONE = VIEW access restriction, CLONE access permission + */ + @Test + public void testTeamMember_VIEW_CLONE() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.CLONE); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertFalse("team member CAN push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * NONE_VIEW = NO access restriction, VIEW access permission + * (not useful scenario) + */ + @Test + public void testTeamMember_NONE_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.NONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.VIEW); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertTrue("team member CAN NOT push!", user.canPush(repository)); + + assertTrue("team member CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("team member CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("team member CAN NOT rewind ref!", user.canRewindRef(repository)); + } + + /** + * PUSH_VIEW = PUSH access restriction, VIEW access permission + */ + @Test + public void testTeamMember_PUSH_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.PUSH; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.VIEW); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertTrue("team member CAN NOT clone!", user.canClone(repository)); + assertFalse("team member CAN push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * CLONE_VIEW = CLONE access restriction, VIEW access permission + */ + @Test + public void testTeamMember_CLONE_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.CLONE; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.VIEW); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertFalse("team member CAN clone!", user.canClone(repository)); + assertFalse("team member CAN push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + /** + * VIEW_VIEW = VIEW access restriction, VIEW access permission + */ + @Test + public void testTeamMember_VIEW_VIEW() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + TeamModel team = new TeamModel("test"); + team.setRepositoryPermission(repository.name, AccessPermission.VIEW); + UserModel user = new UserModel("test"); + user.teams.add(team); + + assertTrue("team member CAN NOT view!", user.canView(repository)); + assertFalse("team member CAN clone!", user.canClone(repository)); + assertFalse("team member CAN push!", user.canPush(repository)); + + assertFalse("team member CAN create ref!", user.canCreateRef(repository)); + assertFalse("team member CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("team member CAN rewind ref!", user.canRewindRef(repository)); + } + + @Test + public void testOwner() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + repository.owner = user.username; + + assertTrue("owner CAN NOT view!", user.canView(repository)); + assertTrue("owner CAN NOT clone!", user.canClone(repository)); + assertTrue("owner CAN NOT push!", user.canPush(repository)); + + assertTrue("owner CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("owner CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("owner CAN NOT rewind ref!", user.canRewindRef(repository)); + + assertTrue("owner CAN NOT fork!", user.canFork(repository)); + + assertFalse("owner CAN NOT delete!", user.canDelete(repository)); + assertTrue("owner CAN NOT edit!", user.canEdit(repository)); + } + + @Test + public void testOwnerPersonalRepository() throws Exception { + RepositoryModel repository = new RepositoryModel("~test/myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + repository.owner = user.username; + + assertTrue("user CAN NOT view!", user.canView(repository)); + assertTrue("user CAN NOT clone!", user.canClone(repository)); + assertTrue("user CAN NOT push!", user.canPush(repository)); + + assertTrue("user CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("user CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("user CAN NOT rewind ref!", user.canRewindRef(repository)); + + assertFalse("user CAN fork!", user.canFork(repository)); + + assertTrue("user CAN NOT delete!", user.canDelete(repository)); + assertTrue("user CAN NOT edit!", user.canEdit(repository)); + } + + @Test + public void testVisitorPersonalRepository() throws Exception { + RepositoryModel repository = new RepositoryModel("~test/myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("visitor"); + repository.owner = "test"; + + assertFalse("user CAN view!", user.canView(repository)); + assertFalse("user CAN clone!", user.canClone(repository)); + assertFalse("user CAN push!", user.canPush(repository)); + + assertFalse("user CAN create ref!", user.canCreateRef(repository)); + assertFalse("user CAN delete ref!", user.canDeleteRef(repository)); + assertFalse("user CAN rewind ref!", user.canRewindRef(repository)); + + assertFalse("user CAN fork!", user.canFork(repository)); + + assertFalse("user CAN delete!", user.canDelete(repository)); + assertFalse("user CAN edit!", user.canEdit(repository)); + } +} diff --git a/tests/com/gitblit/tests/RpcTests.java b/tests/com/gitblit/tests/RpcTests.java index 1080849c..3ad0ec59 100644 --- a/tests/com/gitblit/tests/RpcTests.java +++ b/tests/com/gitblit/tests/RpcTests.java @@ -247,7 +247,7 @@ public class RpcTests { // Create the A-Team TeamModel aTeam = new TeamModel("A-Team"); aTeam.users.add("admin"); - aTeam.repositories.add("helloworld.git"); + aTeam.addRepositoryPermission("helloworld.git"); assertTrue(RpcUtils.createTeam(aTeam, url, account, password.toCharArray())); aTeam = null; @@ -261,7 +261,7 @@ public class RpcTests { } assertNotNull(aTeam); assertTrue(aTeam.hasUser("admin")); - assertTrue(aTeam.hasRepository("helloworld.git")); + assertTrue(aTeam.hasRepositoryPermission("helloworld.git")); RepositoryModel helloworld = null; Map repositories = RpcUtils.getRepositories(url, account, diff --git a/tests/com/gitblit/tests/UserServiceTest.java b/tests/com/gitblit/tests/UserServiceTest.java index 03051bdb..710d1f35 100644 --- a/tests/com/gitblit/tests/UserServiceTest.java +++ b/tests/com/gitblit/tests/UserServiceTest.java @@ -25,8 +25,10 @@ import java.io.IOException; import org.junit.Test; import com.gitblit.ConfigUserService; +import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.FileUserService; import com.gitblit.IUserService; +import com.gitblit.models.RepositoryModel; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; @@ -74,9 +76,9 @@ public class UserServiceTest { // add new user UserModel newUser = new UserModel("test"); newUser.password = "testPassword"; - newUser.addRepository("repo1"); - newUser.addRepository("repo2"); - newUser.addRepository("sub/repo3"); + newUser.addRepositoryPermission("repo1"); + newUser.addRepositoryPermission("repo2"); + newUser.addRepositoryPermission("sub/repo3"); service.updateUserModel(newUser); // add one more new user and then test reload of first new user @@ -93,10 +95,10 @@ public class UserServiceTest { // confirm reloaded test user newUser = service.getUserModel("test"); assertEquals("testPassword", newUser.password); - assertEquals(3, newUser.repositories.size()); - assertTrue(newUser.hasRepository("repo1")); - assertTrue(newUser.hasRepository("repo2")); - assertTrue(newUser.hasRepository("sub/repo3")); + assertEquals(3, newUser.permissions.size()); + assertTrue(newUser.hasRepositoryPermission("repo1")); + assertTrue(newUser.hasRepositoryPermission("repo2")); + assertTrue(newUser.hasRepositoryPermission("sub/repo3")); // confirm authentication of test user UserModel testUser = service.authenticate("test", "testPassword".toCharArray()); @@ -106,7 +108,7 @@ public class UserServiceTest { // delete a repository role and confirm role removal from test user service.deleteRepositoryRole("repo2"); testUser = service.getUserModel("test"); - assertEquals(2, testUser.repositories.size()); + assertEquals(2, testUser.permissions.size()); // delete garbage user and confirm user count service.deleteUser("garbage"); @@ -115,7 +117,7 @@ public class UserServiceTest { // rename repository and confirm role change for test user service.renameRepositoryRole("repo1", "newrepo1"); testUser = service.getUserModel("test"); - assertTrue(testUser.hasRepository("newrepo1")); + assertTrue(testUser.hasRepositoryPermission("newrepo1")); } protected void testTeams(IUserService service) { @@ -123,41 +125,51 @@ public class UserServiceTest { // confirm we have 1 team (admins) assertEquals(1, service.getAllTeamNames().size()); assertEquals("admins", service.getAllTeamNames().get(0)); + + RepositoryModel newrepo1 = new RepositoryModel("newrepo1", null, null, null); + newrepo1.accessRestriction = AccessRestrictionType.VIEW; + RepositoryModel NEWREPO1 = new RepositoryModel("NEWREPO1", null, null, null); + NEWREPO1.accessRestriction = AccessRestrictionType.VIEW; // remove newrepo1 from test user // now test user has no repositories UserModel user = service.getUserModel("test"); - user.repositories.clear(); + user.permissions.clear(); service.updateUserModel(user); user = service.getUserModel("test"); - assertEquals(0, user.repositories.size()); - assertFalse(user.canAccessRepository("newrepo1")); - assertFalse(user.canAccessRepository("NEWREPO1")); + assertEquals(0, user.permissions.size()); + assertFalse(user.canView(newrepo1)); + assertFalse(user.canView(NEWREPO1)); // create test team and add test user and newrepo1 TeamModel team = new TeamModel("testteam"); team.addUser("test"); - team.addRepository("newrepo1"); + team.addRepositoryPermission(newrepo1.name); service.updateTeamModel(team); // confirm 1 user and 1 repo team = service.getTeamModel("testteam"); - assertEquals(1, team.repositories.size()); + assertEquals(1, team.permissions.size()); assertEquals(1, team.users.size()); // confirm team membership user = service.getUserModel("test"); - assertEquals(0, user.repositories.size()); + assertEquals(0, user.permissions.size()); assertEquals(1, user.teams.size()); // confirm team access - assertTrue(team.hasRepository("newrepo1")); - assertTrue(user.hasTeamAccess("newrepo1")); - assertTrue(team.hasRepository("NEWREPO1")); - assertTrue(user.hasTeamAccess("NEWREPO1")); + assertTrue(team.hasRepositoryPermission(newrepo1.name)); + assertTrue(user.canView(newrepo1)); + assertTrue(team.hasRepositoryPermission(NEWREPO1.name)); + assertTrue(user.canView(NEWREPO1)); // rename the team and add new repository - team.addRepository("newrepo2"); + RepositoryModel newrepo2 = new RepositoryModel("newrepo2", null, null, null); + newrepo2.accessRestriction = AccessRestrictionType.VIEW; + RepositoryModel NEWREPO2 = new RepositoryModel("NEWREPO2", null, null, null); + NEWREPO2.accessRestriction = AccessRestrictionType.VIEW; + + team.addRepositoryPermission(newrepo2.name); team.name = "testteam2"; service.updateTeamModel("testteam", team); @@ -165,11 +177,11 @@ public class UserServiceTest { user = service.getUserModel("test"); // confirm user and team can access newrepo2 - assertEquals(2, team.repositories.size()); - assertTrue(team.hasRepository("newrepo2")); - assertTrue(user.hasTeamAccess("newrepo2")); - assertTrue(team.hasRepository("NEWREPO2")); - assertTrue(user.hasTeamAccess("NEWREPO2")); + assertEquals(2, team.permissions.size()); + assertTrue(team.hasRepositoryPermission(newrepo2.name)); + assertTrue(user.canView(newrepo2)); + assertTrue(team.hasRepositoryPermission(NEWREPO2.name)); + assertTrue(user.canView(NEWREPO2)); // delete testteam2 service.deleteTeam("testteam2"); @@ -178,28 +190,28 @@ public class UserServiceTest { // confirm team does not exist and user can not access newrepo1 and 2 assertEquals(null, team); - assertFalse(user.canAccessRepository("newrepo1")); - assertFalse(user.canAccessRepository("newrepo2")); + assertFalse(user.canView(newrepo1)); + assertFalse(user.canView(newrepo2)); // create new team and add it to user // this tests the inverse team creation/team addition team = new TeamModel("testteam"); - team.addRepository("NEWREPO1"); - team.addRepository("NEWREPO2"); + team.addRepositoryPermission(NEWREPO1.name); + team.addRepositoryPermission(NEWREPO2.name); user.teams.add(team); service.updateUserModel(user); // confirm the inverted team addition user = service.getUserModel("test"); team = service.getTeamModel("testteam"); - assertTrue(user.hasTeamAccess("newrepo1")); - assertTrue(user.hasTeamAccess("newrepo2")); + assertTrue(user.canView(newrepo1)); + assertTrue(user.canView(newrepo2)); assertTrue(team.hasUser("test")); // drop testteam from user and add nextteam to user team = new TeamModel("nextteam"); - team.addRepository("NEWREPO1"); - team.addRepository("NEWREPO2"); + team.addRepositoryPermission(NEWREPO1.name); + team.addRepositoryPermission(NEWREPO2.name); user.teams.clear(); user.teams.add(team); service.updateUserModel(user); @@ -207,8 +219,8 @@ public class UserServiceTest { // confirm implicit drop user = service.getUserModel("test"); team = service.getTeamModel("testteam"); - assertTrue(user.hasTeamAccess("newrepo1")); - assertTrue(user.hasTeamAccess("newrepo2")); + assertTrue(user.canView(newrepo1)); + assertTrue(user.canView(newrepo2)); assertFalse(team.hasUser("test")); team = service.getTeamModel("nextteam"); assertTrue(team.hasUser("test"));