James Moger
2011-10-25 486ee115abb831b2ec78be6777fb1bca9e931df0
commit | author | age
ca9d0f 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.io.IOException;
19 import java.text.MessageFormat;
20
21 import javax.servlet.FilterChain;
22 import javax.servlet.ServletException;
23 import javax.servlet.ServletRequest;
24 import javax.servlet.ServletResponse;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27
28 import com.gitblit.Constants.RpcRequest;
29 import com.gitblit.models.UserModel;
30
31 /**
32  * The RpcFilter is a servlet filter that secures the RpcServlet.
33  * 
34  * The filter extracts the rpc request type from the url and determines if the
35  * requested action requires a Basic authentication prompt. If authentication is
36  * required and no credentials are stored in the "Authorization" header, then a
37  * basic authentication challenge is issued.
38  * 
39  * http://en.wikipedia.org/wiki/Basic_access_authentication
40  * 
41  * @author James Moger
42  * 
43  */
44 public class RpcFilter extends AuthenticationFilter {
45
46     /**
47      * doFilter does the actual work of preprocessing the request to ensure that
48      * the user may proceed.
49      * 
50      * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
51      *      javax.servlet.ServletResponse, javax.servlet.FilterChain)
52      */
53     @Override
54     public void doFilter(final ServletRequest request, final ServletResponse response,
55             final FilterChain chain) throws IOException, ServletException {
56
57         HttpServletRequest httpRequest = (HttpServletRequest) request;
58         HttpServletResponse httpResponse = (HttpServletResponse) response;
59
60         String fullUrl = getFullUrl(httpRequest);
61         RpcRequest requestType = RpcRequest.fromName(httpRequest.getParameter("req"));
b2fde8 62         if (requestType == null) {
d03aff 63             httpResponse.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
b2fde8 64             return;
JM 65         }
ca9d0f 66
JM 67         boolean adminRequest = requestType.exceeds(RpcRequest.LIST_REPOSITORIES);
68
841651 69         // conditionally reject all rpc requests
JM 70         if (!GitBlit.getBoolean(Keys.web.enableRpcServlet, true)) {
71             logger.warn(Keys.web.enableRpcServlet + " must be set TRUE for rpc requests.");
72             httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
73             return;
74         }
75
ca9d0f 76         boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, false);
JM 77         boolean authenticateAdmin = GitBlit.getBoolean(Keys.web.authenticateAdminPages, true);
d03aff 78
JM 79         // Wrap the HttpServletRequest with the RpcServletRequest which
ca9d0f 80         // overrides the servlet container user principal methods.
JM 81         AuthenticatedRequest authenticatedRequest = new AuthenticatedRequest(httpRequest);
82         UserModel user = getUser(httpRequest);
83         if (user != null) {
84             authenticatedRequest.setUser(user);
85         }
d03aff 86
JM 87         // conditionally reject rpc management/administration requests
88         if (adminRequest && !GitBlit.getBoolean(Keys.web.enableRpcManagement, false)) {
89             logger.warn(Keys.web.enableRpcManagement
90                     + " must be set TRUE for management/administrative rpc requests.");
841651 91             httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
JM 92             return;
93         }
d03aff 94
ca9d0f 95         // BASIC authentication challenge and response processing
JM 96         if ((adminRequest && authenticateAdmin) || (!adminRequest && authenticateView)) {
97             if (user == null) {
98                 // challenge client to provide credentials. send 401.
99                 if (GitBlit.isDebugMode()) {
100                     logger.info(MessageFormat.format("RPC: CHALLENGE {0}", fullUrl));
101
102                 }
103                 httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
104                 httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
105                 return;
106             } else {
107                 // check user access for request
108                 if (user.canAdmin || canAccess(user, requestType)) {
109                     // authenticated request permitted.
110                     // pass processing to the restricted servlet.
111                     newSession(authenticatedRequest, httpResponse);
112                     logger.info(MessageFormat.format("RPC: {0} ({1}) authenticated", fullUrl,
113                             HttpServletResponse.SC_CONTINUE));
114                     chain.doFilter(authenticatedRequest, httpResponse);
115                     return;
116                 }
117                 // valid user, but not for requested access. send 403.
118                 if (GitBlit.isDebugMode()) {
119                     logger.info(MessageFormat.format("RPC: {0} forbidden to access {1}",
120                             user.username, fullUrl));
121                 }
122                 httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
123                 return;
124             }
125         }
126
127         if (GitBlit.isDebugMode()) {
128             logger.info(MessageFormat.format("RPC: {0} ({1}) unauthenticated", fullUrl,
129                     HttpServletResponse.SC_CONTINUE));
130         }
131         // unauthenticated request permitted.
132         // pass processing to the restricted servlet.
133         chain.doFilter(authenticatedRequest, httpResponse);
134     }
135
136     private boolean canAccess(UserModel user, RpcRequest requestType) {
137         switch (requestType) {
138         case LIST_REPOSITORIES:
139             return true;
140         default:
141             return user.canAdmin;
142         }
143     }
144 }