James Moger
2012-02-03 b7403152813c7fee783e3c999c7f7ae9fbaacce0
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
35     protected final String gitReceivePack = "/git-receive-pack";
36
37     protected final String gitUploadPack = "/git-upload-pack";
38
39     protected final String[] suffixes = { gitReceivePack, gitUploadPack, "/info/refs", "/HEAD",
40             "/objects" };
41
892570 42     /**
JM 43      * Extract the repository name from the url.
44      * 
45      * @param url
46      * @return repository name
47      */
8c9a20 48     @Override
JM 49     protected String extractRepositoryName(String url) {
50         String repository = url;
892570 51         // get the repository name from the url by finding a known url suffix
8c9a20 52         for (String urlSuffix : suffixes) {
JM 53             if (repository.indexOf(urlSuffix) > -1) {
54                 repository = repository.substring(0, repository.indexOf(urlSuffix));
55             }
56         }
57         return repository;
58     }
59
892570 60     /**
JM 61      * Analyze the url and returns the action of the request. Return values are
62      * either "/git-receive-pack" or "/git-upload-pack".
63      * 
831469 64      * @param serverUrl
892570 65      * @return action of the request
JM 66      */
8c9a20 67     @Override
892570 68     protected String getUrlRequestAction(String suffix) {
8c9a20 69         if (!StringUtils.isEmpty(suffix)) {
JM 70             if (suffix.startsWith(gitReceivePack)) {
71                 return gitReceivePack;
72             } else if (suffix.startsWith(gitUploadPack)) {
73                 return gitUploadPack;
74             } else if (suffix.contains("?service=git-receive-pack")) {
75                 return gitReceivePack;
76             } else if (suffix.contains("?service=git-upload-pack")) {
77                 return gitUploadPack;
d40adc 78             } else {
JM 79                 return gitUploadPack;
8c9a20 80             }
JM 81         }
82         return null;
83     }
b74031 84     
JM 85     /**
86      * Determine if the repository can receive pushes.
87      * 
88      * @param repository
89      * @param action
90      * @return true if the action may be performed
91      */
92     @Override
93     protected boolean isActionAllowed(RepositoryModel repository, String action) {
94         if (action.equals(gitReceivePack)) {
95             // Push request
96             if (!repository.isBare) {
97                 logger.warn("Gitblit does not allow pushes to repositories with a working copy");
98                 return false;
99             }
100         }
101         return true;
102     }
8c9a20 103
892570 104     /**
JM 105      * Determine if the repository requires authentication.
106      * 
107      * @param repository
108      * @return true if authentication required
109      */
8c9a20 110     @Override
JM 111     protected boolean requiresAuthentication(RepositoryModel repository) {
112         return repository.accessRestriction.atLeast(AccessRestrictionType.PUSH);
113     }
114
892570 115     /**
JM 116      * Determine if the user can access the repository and perform the specified
117      * action.
118      * 
119      * @param repository
120      * @param user
121      * @param action
122      * @return true if user may execute the action on the repository
123      */
8c9a20 124     @Override
892570 125     protected boolean canAccess(RepositoryModel repository, UserModel user, String action) {
5450d0 126         if (!GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
JM 127             // Git Servlet disabled
128             return false;
b74031 129         }        
JM 130         boolean readOnly = repository.isFrozen;    
831469 131         if (readOnly || repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) {
efe8ec 132             boolean authorizedUser = user.canAccessRepository(repository);
892570 133             if (action.equals(gitReceivePack)) {
8c9a20 134                 // Push request
831469 135                 if (!readOnly && authorizedUser) {
8c9a20 136                     // clone-restricted or push-authorized
JM 137                     return true;
138                 } else {
139                     // user is unauthorized to push to this repository
140                     logger.warn(MessageFormat.format("user {0} is not authorized to push to {1}",
141                             user.username, repository));
142                     return false;
143                 }
892570 144             } else if (action.equals(gitUploadPack)) {
8c9a20 145                 // Clone request
JM 146                 boolean cloneRestricted = repository.accessRestriction
147                         .atLeast(AccessRestrictionType.CLONE);
148                 if (!cloneRestricted || (cloneRestricted && authorizedUser)) {
149                     // push-restricted or clone-authorized
150                     return true;
151                 } else {
152                     // user is unauthorized to clone this repository
153                     logger.warn(MessageFormat.format("user {0} is not authorized to clone {1}",
154                             user.username, repository));
155                     return false;
156                 }
157             }
158         }
159         return true;
160     }
161 }