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