James Moger
2015-11-22 ed552ba47c02779c270ffd62841d6d1048dade70
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  */
7bf6e1 16 package com.gitblit.servlet;
8c9a20 17
13a3f5 18 import java.io.IOException;
JM 19 import java.text.MessageFormat;
20
cdb2fe 21 import com.google.inject.Inject;
JM 22 import com.google.inject.Singleton;
13a3f5 23 import javax.servlet.FilterChain;
JM 24 import javax.servlet.ServletException;
25 import javax.servlet.ServletRequest;
26 import javax.servlet.ServletResponse;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29
8c9a20 30 import com.gitblit.Constants.AccessRestrictionType;
1b34b0 31 import com.gitblit.manager.IAuthenticationManager;
db4f6b 32 import com.gitblit.manager.IProjectManager;
JM 33 import com.gitblit.manager.IRepositoryManager;
34 import com.gitblit.manager.IRuntimeManager;
13a3f5 35 import com.gitblit.models.ProjectModel;
8c9a20 36 import com.gitblit.models.RepositoryModel;
JM 37 import com.gitblit.models.UserModel;
38
892570 39 /**
13a3f5 40  * The SyndicationFilter is an AuthenticationFilter which ensures that feed
JM 41  * requests for projects or view-restricted repositories have proper authentication
892570 42  * credentials and are authorized for the requested feed.
699e71 43  *
892570 44  * @author James Moger
699e71 45  *
892570 46  */
1b34b0 47 @Singleton
13a3f5 48 public class SyndicationFilter extends AuthenticationFilter {
8c9a20 49
65d5bb 50     private IRuntimeManager runtimeManager;
JM 51     private IRepositoryManager repositoryManager;
52     private IProjectManager projectManager;
cacf8b 53
1b34b0 54     @Inject
JM 55     public SyndicationFilter(
56             IRuntimeManager runtimeManager,
57             IAuthenticationManager authenticationManager,
58             IRepositoryManager repositoryManager,
59             IProjectManager projectManager) {
60         super(authenticationManager);
61
62         this.runtimeManager = runtimeManager;
63         this.repositoryManager = repositoryManager;
64         this.projectManager = projectManager;
116422 65     }
JM 66
892570 67     /**
JM 68      * Extract the repository name from the url.
699e71 69      *
892570 70      * @param url
JM 71      * @return repository name
72      */
13a3f5 73     protected String extractRequestedName(String url) {
565ee0 74         if (url.indexOf('?') > -1) {
JM 75             return url.substring(0, url.indexOf('?'));
76         }
8c9a20 77         return url;
JM 78     }
79
892570 80     /**
13a3f5 81      * doFilter does the actual work of preprocessing the request to ensure that
JM 82      * the user may proceed.
699e71 83      *
13a3f5 84      * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
JM 85      *      javax.servlet.ServletResponse, javax.servlet.FilterChain)
892570 86      */
8c9a20 87     @Override
13a3f5 88     public void doFilter(final ServletRequest request, final ServletResponse response,
JM 89             final FilterChain chain) throws IOException, ServletException {
8c9a20 90
13a3f5 91         HttpServletRequest httpRequest = (HttpServletRequest) request;
JM 92         HttpServletResponse httpResponse = (HttpServletResponse) response;
8c9a20 93
13a3f5 94         String fullUrl = getFullUrl(httpRequest);
JM 95         String name = extractRequestedName(fullUrl);
db4f6b 96
JM 97         ProjectModel project = projectManager.getProjectModel(name);
13a3f5 98         RepositoryModel model = null;
699e71 99
13a3f5 100         if (project == null) {
JM 101             // try loading a repository model
db4f6b 102             model = repositoryManager.getRepositoryModel(name);
13a3f5 103             if (model == null) {
JM 104                 // repository not found. send 404.
105                 logger.info(MessageFormat.format("ARF: {0} ({1})", fullUrl,
106                         HttpServletResponse.SC_NOT_FOUND));
107                 httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
108                 return;
109             }
110         }
699e71 111
13a3f5 112         // Wrap the HttpServletRequest with the AccessRestrictionRequest which
JM 113         // overrides the servlet container user principal methods.
114         // JGit requires either:
115         //
116         // 1. servlet container authenticated user
117         // 2. http.receivepack = true in each repository's config
118         //
119         // Gitblit must conditionally authenticate users per-repository so just
120         // enabling http.receivepack is insufficient.
121         AuthenticatedRequest authenticatedRequest = new AuthenticatedRequest(httpRequest);
122         UserModel user = getUser(httpRequest);
123         if (user != null) {
124             authenticatedRequest.setUser(user);
125         }
126
127         // BASIC authentication challenge and response processing
128         if (model != null) {
129             if (model.accessRestriction.atLeast(AccessRestrictionType.VIEW)) {
130                 if (user == null) {
131                     // challenge client to provide credentials. send 401.
db4f6b 132                     if (runtimeManager.isDebugMode()) {
13a3f5 133                         logger.info(MessageFormat.format("ARF: CHALLENGE {0}", fullUrl));
JM 134                     }
135                     httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
136                     httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
137                     return;
138                 } else {
139                     // check user access for request
20714a 140                     if (user.canView(model)) {
13a3f5 141                         // authenticated request permitted.
JM 142                         // pass processing to the restricted servlet.
143                         newSession(authenticatedRequest, httpResponse);
144                         logger.info(MessageFormat.format("ARF: {0} ({1}) authenticated", fullUrl,
145                                 HttpServletResponse.SC_CONTINUE));
146                         chain.doFilter(authenticatedRequest, httpResponse);
147                         return;
148                     }
149                     // valid user, but not for requested access. send 403.
db4f6b 150                     if (runtimeManager.isDebugMode()) {
13a3f5 151                         logger.info(MessageFormat.format("ARF: {0} forbidden to access {1}",
JM 152                                 user.username, fullUrl));
153                     }
154                     httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
155                     return;
156                 }
157             }
158         }
159
db4f6b 160         if (runtimeManager.isDebugMode()) {
13a3f5 161             logger.info(MessageFormat.format("ARF: {0} ({1}) unauthenticated", fullUrl,
JM 162                     HttpServletResponse.SC_CONTINUE));
163         }
164         // unauthenticated request permitted.
165         // pass processing to the restricted servlet.
166         chain.doFilter(authenticatedRequest, httpResponse);
167     }
8c9a20 168 }