James Moger
2012-10-10 20714aee0d2d2a989d93d6065e081aed8ac85fbf
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
3 files added
31 files modified
3792 ■■■■■ changed files
docs/01_features.mkd 13 ●●●● patch | view | raw | blame | history
docs/01_setup.mkd 68 ●●●● patch | view | raw | blame | history
docs/04_releases.mkd 16 ●●●● patch | view | raw | blame | history
docs/permissions_matrix.ods patch | view | raw | blame | history
docs/permissions_matrix.png patch | view | raw | blame | history
src/com/gitblit/ConfigUserService.java 148 ●●●● patch | view | raw | blame | history
src/com/gitblit/Constants.java 72 ●●●●● patch | view | raw | blame | history
src/com/gitblit/DownloadZipFilter.java 2 ●●● patch | view | raw | blame | history
src/com/gitblit/FederationPullExecutor.java 49 ●●●● patch | view | raw | blame | history
src/com/gitblit/FileUserService.java 142 ●●●● patch | view | raw | blame | history
src/com/gitblit/GitBlit.java 75 ●●●●● patch | view | raw | blame | history
src/com/gitblit/GitFilter.java 46 ●●●●● patch | view | raw | blame | history
src/com/gitblit/GitServlet.java 35 ●●●●● patch | view | raw | blame | history
src/com/gitblit/GitblitUserService.java 12 ●●●●● patch | view | raw | blame | history
src/com/gitblit/IUserService.java 22 ●●●●● patch | view | raw | blame | history
src/com/gitblit/PagesFilter.java 2 ●●● patch | view | raw | blame | history
src/com/gitblit/SyndicationFilter.java 2 ●●● patch | view | raw | blame | history
src/com/gitblit/models/RepositoryModel.java 7 ●●●●● patch | view | raw | blame | history
src/com/gitblit/models/TeamModel.java 135 ●●●●● patch | view | raw | blame | history
src/com/gitblit/models/UserModel.java 187 ●●●● patch | view | raw | blame | history
src/com/gitblit/utils/JsonUtils.java 20 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/BasePage.java 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/ForkPage.java 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/ForksPage.java 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/RepositoryPage.java 4 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/RootPage.java 2 ●●● patch | view | raw | blame | history
tests/com/gitblit/tests/FederationTests.java 2 ●●● patch | view | raw | blame | history
tests/com/gitblit/tests/GitBlitSuite.java 2 ●●● patch | view | raw | blame | history
tests/com/gitblit/tests/GitBlitTest.java 23 ●●●● patch | view | raw | blame | history
tests/com/gitblit/tests/GitServletTest.java 217 ●●●●● patch | view | raw | blame | history
tests/com/gitblit/tests/JGitUtilsTest.java 4 ●●● patch | view | raw | blame | history
tests/com/gitblit/tests/PermissionsTest.java 2391 ●●●●● patch | view | raw | blame | history
tests/com/gitblit/tests/RpcTests.java 4 ●●●● patch | view | raw | blame | history
tests/com/gitblit/tests/UserServiceTest.java 84 ●●●●● patch | view | raw | blame | history
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
docs/01_setup.mkd
@@ -244,6 +244,25 @@
#### 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 @@
        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 @@
        user = faceman
        user = murdock
        user = babaracus
        repository = topsecret.git
        repository = RW:topsecret.git
        mailingList = list@ateam.org
        postReceiveScript = sendmail
@@ -291,15 +311,49 @@
    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
docs/04_releases.mkd
@@ -17,18 +17,26 @@
- 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 <u>however</u> 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
docs/permissions_matrix.ods
Binary files differ
docs/permissions_matrix.png
src/com/gitblit/ConfigUserService.java
@@ -33,6 +33,7 @@
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;
@@ -268,6 +269,55 @@
    }
    /**
     * 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<UserModel> 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 @@
            read();
            for (Map.Entry<String, TeamModel> entry : teams.entrySet()) {
                TeamModel model = entry.getValue();
                if (model.hasRepository(role)) {
                if (model.hasRepositoryPermission(role)) {
                    list.add(model.name);
                }
            }
@@ -447,10 +497,10 @@
            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);
                }
            }
@@ -492,6 +542,28 @@
    @Override
    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
     */
    @Override
    public boolean updateTeamModels(List<TeamModel> 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;
    }
    /**
@@ -602,7 +674,7 @@
            read();
            for (Map.Entry<String, UserModel> entry : users.entrySet()) {
                UserModel model = entry.getValue();
                if (model.hasRepository(role)) {
                if (model.hasRepositoryPermission(role)) {
                    list.add(model.username);
                }
            }
@@ -623,6 +695,7 @@
     * @return true if successful
     */
    @Override
    @Deprecated
    public boolean setUsernamesForRepositoryRole(String role, List<String> usernames) {
        try {
            Set<String> specifiedUsers = new HashSet<String>();
@@ -636,10 +709,10 @@
            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 @@
            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 @@
            // 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 @@
            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<String>(
                        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<String>(
                            model.repositories));
                }
            } else {
                // discrete repository permissions
                List<String> permissions = new ArrayList<String>();
                for (Map.Entry<String, AccessPermission> 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<String>(
                        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<String>(
                            model.repositories));
                }
            } else {
                // discrete repository permissions
                List<String> permissions = new ArrayList<String>();
                for (Map.Entry<String, AccessPermission> 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 @@
                    Set<String> repositories = new HashSet<String>(Arrays.asList(config
                            .getStringList(USER, username, REPOSITORY)));
                    for (String repository : repositories) {
                        user.addRepository(repository);
                        user.addRepositoryPermission(repository);
                    }
                    // update cache
@@ -886,7 +982,7 @@
                Set<String> 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,
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 @@
            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 {
    }
}
src/com/gitblit/DownloadZipFilter.java
@@ -91,7 +91,7 @@
     */
    @Override
    protected boolean canAccess(RepositoryModel repository, UserModel user, String action) {
        return user.canAccessRepository(repository);
        return user.canView(repository);
    }
}
src/com/gitblit/FederationPullExecutor.java
@@ -26,6 +26,7 @@
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.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 @@
                        // reparent all repository permissions if the local
                        // repositories are stored within subfolders
                        if (!StringUtils.isEmpty(registrationFolder)) {
                            List<String> permissions = new ArrayList<String>(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<String, AccessPermission> copy = new HashMap<String, AccessPermission>(user.permissions);
                                user.permissions.clear();
                                for (Map.Entry<String, AccessPermission> entry : copy.entrySet()) {
                                    user.setRepositoryPermission(registrationFolder + "/" + entry.getKey(), entry.getValue());
                                }
                            } else {
                                // pulling from <= 1.1 version
                                List<String> permissions = new ArrayList<String>(user.repositories);
                                user.repositories.clear();
                                for (String permission : permissions) {
                                    user.addRepositoryPermission(registrationFolder + "/" + permission);
                                }
                            }
                        }
@@ -347,8 +359,17 @@
                            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<String, AccessPermission> copy = new HashMap<String, AccessPermission>(user.permissions);
                                for (Map.Entry<String, AccessPermission> 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 @@
                            // 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<String, AccessPermission> 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);
                                }
                            }
src/com/gitblit/FileUserService.java
@@ -31,6 +31,7 @@
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 @@
                }
                break;
            default:
                model.addRepository(role);
                model.addRepositoryPermission(role);
            }
        }
        // set the teams for the user
@@ -267,6 +268,29 @@
    }
    /**
     * 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<UserModel> 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 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<String> roles = new ArrayList<String>(model.repositories);
            List<String> roles;
            if (model.permissions == null) {
                // legacy, use repository list
                roles = new ArrayList<String>(model.repositories);
            } else {
                // discrete repository permissions
                roles = new ArrayList<String>();
                for (Map.Entry<String, AccessPermission> 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 @@
                    }
                }
            }
            write(allUsers);
            return true;
        } catch (Throwable t) {
            logger.error(MessageFormat.format("Failed to update user model {0}!", model.username),
@@ -552,8 +609,8 @@
                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 @@
                // 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 @@
                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 @@
                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 @@
                            repositories.add(role);
                        }
                    }
                    team.addRepositories(repositories);
                    team.addRepositoryPermissions(repositories);
                    team.addUsers(users);
                    team.addMailingLists(mailingLists);
                    team.preReceiveScripts.addAll(preReceive);
@@ -912,6 +973,27 @@
    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<TeamModel> 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 @@
    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<String> roles;
        if (model.permissions == null) {
            // legacy, use repository list
            if (model.repositories != null) {
                roles = new ArrayList<String>(model.repositories);
            } else {
                roles = new ArrayList<String>();
            }
        } else {
            // discrete repository permissions
            roles = new ArrayList<String>();
            for (Map.Entry<String, AccessPermission> 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('!');
src/com/gitblit/GitBlit.java
@@ -69,6 +69,7 @@
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 @@
     * @param usernames
     * @return true if successful
     */
    @Deprecated
    public boolean setRepositoryUsers(RepositoryModel repository, List<String> repositoryUsers) {
        return userService.setUsernamesForRepositoryRole(repository.name, repositoryUsers);
    }
@@ -699,6 +701,7 @@
     * @param teamnames
     * @return true if successful
     */
    @Deprecated
    public boolean setRepositoryTeams(RepositoryModel repository, List<String> repositoryTeams) {
        return userService.setTeamnamesForRepositoryRole(repository.name, repositoryTeams);
    }
@@ -957,14 +960,13 @@
        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 @@
        }
        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 @@
     */
    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 @@
            clearRepositoryMetadataCache(repositoryName);
            
            RepositoryModel model = removeFromCachedRepositoryList(repositoryName);
            if (!ArrayUtils.isEmpty(model.forks)) {
            if (model != null && !ArrayUtils.isEmpty(model.forks)) {
                resetRepositoryListCache();
            }
@@ -2646,27 +2647,47 @@
        // 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<String> users = getRepositoryUsers(repository);
            setRepositoryUsers(cloneModel, users);
            List<String> teams = getRepositoryTeams(repository);
            setRepositoryTeams(cloneModel, teams);
        }
        // grant origin's user list clone permission to fork
        List<String> users = getRepositoryUsers(repository);
        List<UserModel> cloneUsers = new ArrayList<UserModel>();
        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);
        // grant origin's team list clone permission to fork
        List<String> teams = getRepositoryTeams(repository);
        List<TeamModel> cloneTeams = new ArrayList<TeamModel>();
        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);
        return cloneModel;
src/com/gitblit/GitFilter.java
@@ -147,33 +147,25 @@
            // 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;
src/com/gitblit/GitServlet.java
@@ -105,6 +105,21 @@
                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 @@
            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);
        }
src/com/gitblit/GitblitUserService.java
@@ -168,6 +168,11 @@
    }
    @Override
    public boolean updateUserModels(List<UserModel> models) {
        return serviceImpl.updateUserModels(models);
    }
    @Override
    public boolean updateUserModel(String username, UserModel model) {
        if (supportsCredentialChanges()) {
            if (!supportsTeamMembershipChanges()) {
@@ -232,6 +237,7 @@
    }
    @Override
    @Deprecated
    public boolean setTeamnamesForRepositoryRole(String role, List<String> teamnames) {
        return serviceImpl.setTeamnamesForRepositoryRole(role, teamnames);
    }
@@ -244,6 +250,11 @@
    @Override
    public boolean updateTeamModel(TeamModel model) {
        return serviceImpl.updateTeamModel(model);
    }
    @Override
    public boolean updateTeamModels(List<TeamModel> models) {
        return serviceImpl.updateTeamModels(models);
    }
    @Override
@@ -275,6 +286,7 @@
    }
    @Override
    @Deprecated
    public boolean setUsernamesForRepositoryRole(String role, List<String> usernames) {
        return serviceImpl.setUsernamesForRepositoryRole(role, usernames);
    }
src/com/gitblit/IUserService.java
@@ -127,6 +127,15 @@
    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<UserModel> models);
    /**
     * Adds/updates a user object keyed by username. This method allows for
     * renaming a user.
     * 
@@ -205,7 +214,8 @@
     * @param teamnames
     * @return true if successful
     * @since 0.8.0
     */
     */
    @Deprecated
    boolean setTeamnamesForRepositoryRole(String role, List<String> teamnames);
    
    /**
@@ -226,6 +236,15 @@
     */    
    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<TeamModel> models);
    /**
     * Updates/writes and replaces a complete team object keyed by teamname.
     * This method allows for renaming a team.
@@ -277,6 +296,7 @@
     * @param usernames
     * @return true if successful
     */
    @Deprecated
    boolean setUsernamesForRepositoryRole(String role, List<String> usernames);
    /**
src/com/gitblit/PagesFilter.java
@@ -111,6 +111,6 @@
     */
    @Override
    protected boolean canAccess(RepositoryModel repository, UserModel user, String action) {        
        return user.canAccessRepository(repository);
        return user.canView(repository);
    }
}
src/com/gitblit/SyndicationFilter.java
@@ -113,7 +113,7 @@
                    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);
src/com/gitblit/models/RepositoryModel.java
@@ -88,7 +88,8 @@
        this.accessRestriction = AccessRestrictionType.NONE;
        this.authorizationControl = AuthorizationControl.NAMED;
        this.federationSets = new ArrayList<String>();
        this.federationStrategy = FederationStrategy.FEDERATE_THIS;
        this.federationStrategy = FederationStrategy.FEDERATE_THIS;
        this.projectPath = StringUtils.getFirstPathElement(name);
    }
    
    public List<String> getLocalBranches() {
@@ -175,8 +176,8 @@
        clone.projectPath = StringUtils.getFirstPathElement(cloneName);
        clone.isBare = true;
        clone.description = description;
        clone.accessRestriction = accessRestriction;
        clone.authorizationControl = authorizationControl;
        clone.accessRestriction = AccessRestrictionType.PUSH;
        clone.authorizationControl = AuthorizationControl.NAMED;
        clone.federationStrategy = federationStrategy;
        clone.showReadme = showReadme;
        clone.showRemoteBranches = false;
src/com/gitblit/models/TeamModel.java
@@ -18,9 +18,15 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.gitblit.Constants.AccessPermission;
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.Constants.Unused;
/**
 * TeamModel is a serializable model class that represents a group of users and
@@ -36,7 +42,10 @@
    // field names are reflectively mapped in EditTeam page
    public String name;
    public final Set<String> users = new HashSet<String>();
    // retained for backwards-compatibility with RPC clients
    @Deprecated
    public final Set<String> repositories = new HashSet<String>();
    public final Map<String, AccessPermission> permissions = new HashMap<String, AccessPermission>();
    public final Set<String> mailingLists = new HashSet<String>();
    public final List<String> preReceiveScripts = new ArrayList<String>();
    public final List<String> postReceiveScripts = new ArrayList<String>();
@@ -45,24 +54,136 @@
        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<String> 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.
     * <p>
     * Role may be formatted as:
     * <ul>
     * <li> myrepo.git <i>(this is implicitly RW+)</i>
     * <li> RW+:myrepo.git
     * </ul>
     * @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<String> 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());
    }
src/com/gitblit/models/UserModel.java
@@ -17,11 +17,15 @@
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 boolean canFork;
    public boolean canCreate;
    public boolean excludeFromFederation;
    // retained for backwards-compatibility with RPC clients
    @Deprecated
    public final Set<String> repositories = new HashSet<String>();
    public final Map<String, AccessPermission> permissions = new HashMap<String, AccessPermission>();
    public final Set<TeamModel> teams = new HashSet<TeamModel>();
    // non-persisted fields
@@ -77,6 +84,8 @@
                || hasTeamAccess(repositoryName);
    }
    @Deprecated
    @Unused
    public boolean canAccessRepository(RepositoryModel repository) {
        boolean isOwner = !StringUtils.isEmpty(repository.owner)
                && repository.owner.equals(username);
@@ -85,62 +94,170 @@
                || 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.
     * <p>
     * Role may be formatted as:
     * <ul>
     * <li> myrepo.git <i>(this is implicitly RW+)</i>
     * <li> RW+:myrepo.git
     * </ul>
     * @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 (repository.accessRestriction.atLeast(AccessRestrictionType.VIEW)) {
            return canAccessRepository(repository);
        if (AuthorizationControl.AUTHENTICATED.equals(repository.authorizationControl) && isAuthenticated) {
            // AUTHENTICATED is a shortcut for authorizing all logged-in users RW access
            return AccessPermission.REWIND;
        }
        // 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) {
    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 canFork(RepositoryModel repository) {
        if (repository.isUsersPersonalRepository(username)) {
            // can not fork your own repository
            return false;
        }
        if (canAdmin || repository.isOwner(username)) {
            return true;
        }
        if (!canFork) {
            // user has been prohibited from forking
            return false;
        }
        if (!isAuthenticated) {
            // unauthenticated user model
            return false;
        }
        if (("~" + username).equalsIgnoreCase(repository.projectPath)) {
            // this repository is already a personal repository
            return false;
        }
        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;
        return canClone(repository);
    }
    public boolean hasRepository(String name) {
        return repositories.contains(name.toLowerCase());
    public boolean canDelete(RepositoryModel model) {
        return canAdmin || model.isUsersPersonalRepository(username);
    }
    public void addRepository(String name) {
        repositories.add(name.toLowerCase());
    }
    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) {
src/com/gitblit/utils/JsonUtils.java
@@ -32,6 +32,7 @@
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 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 @@
            }
        }
    }
    private static class AccessPermissionTypeAdapter implements JsonSerializer<AccessPermission>, JsonDeserializer<AccessPermission> {
        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 {
src/com/gitblit/wicket/pages/BasePage.java
@@ -297,7 +297,7 @@
            for (ProjectModel projectModel : availableModels) {
                for (String repositoryName : projectModel.repositories) {
                    for (TeamModel teamModel : teamModels) {
                        if (teamModel.hasRepository(repositoryName)) {
                        if (teamModel.hasRepositoryPermission(repositoryName)) {
                            models.add(projectModel);
                        }
                    }
src/com/gitblit/wicket/pages/ForkPage.java
@@ -40,7 +40,7 @@
        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
src/com/gitblit/wicket/pages/ForksPage.java
@@ -94,7 +94,7 @@
                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)));
src/com/gitblit/wicket/pages/RepositoryPage.java
@@ -209,7 +209,7 @@
            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 @@
        } 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
src/com/gitblit/wicket/pages/RootPage.java
@@ -418,7 +418,7 @@
            // 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);
                    }
                }
tests/com/gitblit/tests/FederationTests.java
@@ -136,7 +136,7 @@
        
        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());
tests/com/gitblit/tests/GitBlitSuite.java
@@ -49,7 +49,7 @@
@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,
tests/com/gitblit/tests/GitBlitTest.java
@@ -52,20 +52,21 @@
        List<String> 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
tests/com/gitblit/tests/GitServletTest.java
@@ -13,18 +13,28 @@
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 @@
        }
        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<PushResult> 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
tests/com/gitblit/tests/JGitUtilsTest.java
@@ -35,6 +35,7 @@
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 @@
            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);
        }
    }
tests/com/gitblit/tests/PermissionsTest.java
New file
@@ -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));
    }
}
tests/com/gitblit/tests/RpcTests.java
@@ -247,7 +247,7 @@
        // 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 @@
        }
        assertNotNull(aTeam);
        assertTrue(aTeam.hasUser("admin"));
        assertTrue(aTeam.hasRepository("helloworld.git"));
        assertTrue(aTeam.hasRepositoryPermission("helloworld.git"));
        RepositoryModel helloworld = null;
        Map<String, RepositoryModel> repositories = RpcUtils.getRepositories(url, account,
tests/com/gitblit/tests/UserServiceTest.java
@@ -25,8 +25,10 @@
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 @@
        // 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 @@
        // 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 @@
        // 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 @@
        // 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 @@
        // 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 @@
        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 @@
        // 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 @@
        // 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"));