James Moger
2012-09-10 fabe060d3a435f116128851f828e35c2af5fde67
commit | author | age
8c9a20 1 /*
JM 2  * Copyright 2011 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.gitblit;
17
18 import java.text.MessageFormat;
19
20 import com.gitblit.Constants.AccessRestrictionType;
21 import com.gitblit.models.RepositoryModel;
22 import com.gitblit.models.UserModel;
23 import com.gitblit.utils.StringUtils;
24
892570 25 /**
JM 26  * The GitFilter is an AccessRestrictionFilter which ensures that Git client
27  * requests for push, clone, or view restricted repositories are authenticated
28  * and authorized.
29  * 
30  * @author James Moger
31  * 
32  */
8c9a20 33 public class GitFilter extends AccessRestrictionFilter {
JM 34
756117 35     protected static final String gitReceivePack = "/git-receive-pack";
8c9a20 36
756117 37     protected static final String gitUploadPack = "/git-upload-pack";
8c9a20 38
756117 39     protected static final String[] suffixes = { gitReceivePack, gitUploadPack, "/info/refs", "/HEAD",
8c9a20 40             "/objects" };
756117 41
JM 42     /**
43      * Extract the repository name from the url.
44      * 
45      * @param url
46      * @return repository name
47      */
48     public static String getRepositoryName(String value) {
49         String repository = value;
50         // get the repository name from the url by finding a known url suffix
51         for (String urlSuffix : suffixes) {
52             if (repository.indexOf(urlSuffix) > -1) {
53                 repository = repository.substring(0, repository.indexOf(urlSuffix));
54             }
55         }
56         return repository;
57     }
8c9a20 58
892570 59     /**
JM 60      * Extract the repository name from the url.
61      * 
62      * @param url
63      * @return repository name
64      */
8c9a20 65     @Override
JM 66     protected String extractRepositoryName(String url) {
756117 67         return GitFilter.getRepositoryName(url);
8c9a20 68     }
JM 69
892570 70     /**
JM 71      * Analyze the url and returns the action of the request. Return values are
72      * either "/git-receive-pack" or "/git-upload-pack".
73      * 
831469 74      * @param serverUrl
892570 75      * @return action of the request
JM 76      */
8c9a20 77     @Override
892570 78     protected String getUrlRequestAction(String suffix) {
8c9a20 79         if (!StringUtils.isEmpty(suffix)) {
JM 80             if (suffix.startsWith(gitReceivePack)) {
81                 return gitReceivePack;
82             } else if (suffix.startsWith(gitUploadPack)) {
83                 return gitUploadPack;
84             } else if (suffix.contains("?service=git-receive-pack")) {
85                 return gitReceivePack;
86             } else if (suffix.contains("?service=git-upload-pack")) {
87                 return gitUploadPack;
d40adc 88             } else {
JM 89                 return gitUploadPack;
8c9a20 90             }
JM 91         }
92         return null;
93     }
b74031 94     
JM 95     /**
96      * Determine if the repository can receive pushes.
97      * 
98      * @param repository
99      * @param action
100      * @return true if the action may be performed
101      */
102     @Override
103     protected boolean isActionAllowed(RepositoryModel repository, String action) {
5930f3 104         if (!StringUtils.isEmpty(action)) {
JM 105             if (action.equals(gitReceivePack)) {
106                 // Push request
107                 if (!repository.isBare) {
108                     logger.warn("Gitblit does not allow pushes to repositories with a working copy");
109                     return false;
110                 }
b74031 111             }
JM 112         }
113         return true;
114     }
8c9a20 115
892570 116     /**
JM 117      * Determine if the repository requires authentication.
118      * 
119      * @param repository
3f8cd4 120      * @param action
892570 121      * @return true if authentication required
JM 122      */
8c9a20 123     @Override
3f8cd4 124     protected boolean requiresAuthentication(RepositoryModel repository, String action) {
JM 125         if (gitUploadPack.equals(action)) {
126             // send to client
127             return repository.accessRestriction.atLeast(AccessRestrictionType.CLONE);    
128         } else if (gitReceivePack.equals(action)) {
129             // receive from client
130             return repository.accessRestriction.atLeast(AccessRestrictionType.PUSH);
131         }
132         return false;
8c9a20 133     }
JM 134
892570 135     /**
JM 136      * Determine if the user can access the repository and perform the specified
137      * action.
138      * 
139      * @param repository
140      * @param user
141      * @param action
142      * @return true if user may execute the action on the repository
143      */
8c9a20 144     @Override
892570 145     protected boolean canAccess(RepositoryModel repository, UserModel user, String action) {
5450d0 146         if (!GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
JM 147             // Git Servlet disabled
148             return false;
b74031 149         }        
JM 150         boolean readOnly = repository.isFrozen;    
831469 151         if (readOnly || repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) {
efe8ec 152             boolean authorizedUser = user.canAccessRepository(repository);
892570 153             if (action.equals(gitReceivePack)) {
8c9a20 154                 // Push request
831469 155                 if (!readOnly && authorizedUser) {
8c9a20 156                     // clone-restricted or push-authorized
JM 157                     return true;
158                 } else {
159                     // user is unauthorized to push to this repository
160                     logger.warn(MessageFormat.format("user {0} is not authorized to push to {1}",
161                             user.username, repository));
162                     return false;
163                 }
892570 164             } else if (action.equals(gitUploadPack)) {
8c9a20 165                 // Clone request
JM 166                 boolean cloneRestricted = repository.accessRestriction
167                         .atLeast(AccessRestrictionType.CLONE);
168                 if (!cloneRestricted || (cloneRestricted && authorizedUser)) {
169                     // push-restricted or clone-authorized
170                     return true;
171                 } else {
172                     // user is unauthorized to clone this repository
173                     logger.warn(MessageFormat.format("user {0} is not authorized to clone {1}",
174                             user.username, repository));
175                     return false;
176                 }
177             }
178         }
179         return true;
180     }
181 }