]> source.dussan.org Git - gitblit.git/commitdiff
Refactored servlet filters and now have authenticated RpcServlet.
authorJames Moger <james.moger@gitblit.com>
Sun, 2 Oct 2011 02:41:01 +0000 (22:41 -0400)
committerJames Moger <james.moger@gitblit.com>
Sun, 2 Oct 2011 02:41:01 +0000 (22:41 -0400)
src/WEB-INF/web.xml
src/com/gitblit/AccessRestrictionFilter.java
src/com/gitblit/AuthenticationFilter.java [new file with mode: 0644]
src/com/gitblit/Constants.java
src/com/gitblit/RpcFilter.java [new file with mode: 0644]
src/com/gitblit/RpcServlet.java

index 0a6cea97d9a57bc1a67b78b7345e6f772396072b..afe4552dd45ae754478b9e88e48172235997a1a6 100644 (file)
                <filter-name>ZipFilter</filter-name>\r
                <url-pattern>/zip/*</url-pattern>\r
        </filter-mapping>\r
+\r
                \r
+       <!-- Rpc Restriction Filter\r
+                <url-pattern> MUST match: \r
+                       * RpcServlet\r
+                       * com.gitblit.Constants.RPC_PATH\r
+                       * Wicket Filter ignorePaths parameter -->\r
+       <filter>\r
+               <filter-name>RpcFilter</filter-name>\r
+               <filter-class>com.gitblit.RpcFilter</filter-class>\r
+       </filter>\r
+       <filter-mapping>\r
+               <filter-name>RpcFilter</filter-name>\r
+               <url-pattern>/rpc/*</url-pattern>\r
+       </filter-mapping>\r
+\r
                \r
        <!-- Wicket Filter -->\r
     <filter>\r
                * ZipServlet <url-pattern>\r
                * com.gitblit.Constants.ZIP_PATH\r
                * FederationServlet <url-pattern>\r
+               * RpcFilter <url-pattern>\r
                * RpcServlet <url-pattern> -->\r
             <param-value>git/,feed/,zip/,federation/,rpc/</param-value>\r
         </init-param>\r
index 25adc5255c46c69b3d3dbd9914d9abcae6237421..27e2a18a7099661f21cced268bc8a91a061055c3 100644 (file)
 package com.gitblit;\r
 \r
 import java.io.IOException;\r
-import java.nio.charset.Charset;\r
-import java.security.Principal;\r
 import java.text.MessageFormat;\r
-import java.util.Enumeration;\r
-import java.util.HashMap;\r
-import java.util.Map;\r
 \r
-import javax.servlet.Filter;\r
 import javax.servlet.FilterChain;\r
-import javax.servlet.FilterConfig;\r
 import javax.servlet.ServletException;\r
 import javax.servlet.ServletRequest;\r
 import javax.servlet.ServletResponse;\r
 import javax.servlet.http.HttpServletRequest;\r
 import javax.servlet.http.HttpServletResponse;\r
-import javax.servlet.http.HttpSession;\r
-\r
-import org.eclipse.jgit.util.Base64;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
 \r
+import com.gitblit.AuthenticationFilter.AuthenticatedRequest;\r
 import com.gitblit.models.RepositoryModel;\r
 import com.gitblit.models.UserModel;\r
 import com.gitblit.utils.StringUtils;\r
 \r
 /**\r
- * The AccessRestrictionFilter is a servlet filter that preprocesses requests\r
- * that match its url pattern definition in the web.xml file.\r
+ * The AccessRestrictionFilter is an AuthenticationFilter that confirms that the\r
+ * requested repository can be accessed by the anonymous or named user.\r
  * \r
  * The filter extracts the name of the repository from the url and determines if\r
  * the requested action for the repository requires a Basic authentication\r
@@ -55,19 +44,7 @@ import com.gitblit.utils.StringUtils;
  * @author James Moger\r
  * \r
  */\r
-public abstract class AccessRestrictionFilter implements Filter {\r
-\r
-       private static final String BASIC = "Basic";\r
-\r
-       private static final String CHALLENGE = BASIC + " realm=\"" + Constants.NAME + "\"";\r
-\r
-       private static final String SESSION_SECURED = "com.gitblit.secured";\r
-\r
-       protected transient Logger logger;\r
-\r
-       public AccessRestrictionFilter() {\r
-               logger = LoggerFactory.getLogger(getClass());\r
-       }\r
+public abstract class AccessRestrictionFilter extends AuthenticationFilter {\r
 \r
        /**\r
         * Extract the repository name from the url.\r
@@ -118,26 +95,7 @@ public abstract class AccessRestrictionFilter implements Filter {
                HttpServletRequest httpRequest = (HttpServletRequest) request;\r
                HttpServletResponse httpResponse = (HttpServletResponse) response;\r
 \r
-               // Wrap the HttpServletRequest with the AccessRestrictionRequest which\r
-               // overrides the servlet container user principal methods.\r
-               // JGit requires either:\r
-               //\r
-               // 1. servlet container authenticated user\r
-               // 2. http.receivepack = true in each repository's config\r
-               //\r
-               // Gitblit must conditionally authenticate users per-repository so just\r
-               // enabling http.receivepack is insufficient.\r
-\r
-               AccessRestrictionRequest accessRequest = new AccessRestrictionRequest(httpRequest);\r
-\r
-               String servletUrl = httpRequest.getContextPath() + httpRequest.getServletPath();\r
-               String url = httpRequest.getRequestURI().substring(servletUrl.length());\r
-               String params = httpRequest.getQueryString();\r
-               if (url.length() > 0 && url.charAt(0) == '/') {\r
-                       url = url.substring(1);\r
-               }\r
-               String fullUrl = url + (StringUtils.isEmpty(params) ? "" : ("?" + params));\r
-\r
+               String fullUrl = getFullUrl(httpRequest);\r
                String repository = extractRepositoryName(fullUrl);\r
 \r
                // Determine if the request URL is restricted\r
@@ -148,145 +106,64 @@ public abstract class AccessRestrictionFilter implements Filter {
                RepositoryModel model = GitBlit.self().getRepositoryModel(repository);\r
                if (model == null) {\r
                        // repository not found. send 404.\r
-                       logger.info("ARF: " + fullUrl + " (" + HttpServletResponse.SC_NOT_FOUND + ")");\r
+                       logger.info(MessageFormat.format("ARF: {0} ({1})", fullUrl,\r
+                                       HttpServletResponse.SC_NOT_FOUND));\r
                        httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);\r
                        return;\r
                }\r
 \r
+               // Wrap the HttpServletRequest with the AccessRestrictionRequest which\r
+               // overrides the servlet container user principal methods.\r
+               // JGit requires either:\r
+               //\r
+               // 1. servlet container authenticated user\r
+               // 2. http.receivepack = true in each repository's config\r
+               //\r
+               // Gitblit must conditionally authenticate users per-repository so just\r
+               // enabling http.receivepack is insufficient.\r
+               AuthenticatedRequest authenticatedRequest = new AuthenticatedRequest(httpRequest);\r
+               UserModel user = getUser(httpRequest);\r
+               if (user != null) {\r
+                       authenticatedRequest.setUser(user);\r
+               }\r
+\r
                // BASIC authentication challenge and response processing\r
                if (!StringUtils.isEmpty(urlRequestType) && requiresAuthentication(model)) {\r
-                       // look for client authorization credentials in header\r
-                       final String authorization = httpRequest.getHeader("Authorization");\r
-                       if (authorization != null && authorization.startsWith(BASIC)) {\r
-                               // Authorization: Basic base64credentials\r
-                               String base64Credentials = authorization.substring(BASIC.length()).trim();\r
-                               String credentials = new String(Base64.decode(base64Credentials),\r
-                                               Charset.forName("UTF-8"));\r
-                               // credentials = username:password\r
-                               final String[] values = credentials.split(":");\r
-\r
-                               if (values.length == 2) {\r
-                                       String username = values[0];\r
-                                       char[] password = values[1].toCharArray();\r
-                                       UserModel user = GitBlit.self().authenticate(username, password);\r
-                                       if (user != null) {\r
-                                               accessRequest.setUser(user);\r
-                                               if (user.canAdmin || canAccess(model, user, urlRequestType)) {\r
-                                                       // authenticated request permitted.\r
-                                                       // pass processing to the restricted servlet.\r
-                                                       newSession(accessRequest, httpResponse);\r
-                                                       logger.info("ARF: " + fullUrl + " (" + HttpServletResponse.SC_CONTINUE\r
-                                                                       + ") authenticated");\r
-                                                       chain.doFilter(accessRequest, httpResponse);\r
-                                                       return;\r
-                                               }\r
-                                               // valid user, but not for requested access. send 403.\r
-                                               if (GitBlit.isDebugMode()) {\r
-                                                       logger.info("ARF: " + fullUrl + " (" + HttpServletResponse.SC_FORBIDDEN\r
-                                                                       + ")");\r
-                                                       logger.info(MessageFormat.format("AUTH: {0} forbidden to access {1}",\r
-                                                                       user.username, url));\r
-                                               }\r
-                                               httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);\r
-                                               return;\r
-                                       }\r
+                       if (user == null) {\r
+                               // challenge client to provide credentials. send 401.\r
+                               if (GitBlit.isDebugMode()) {\r
+                                       logger.info(MessageFormat.format("ARF: CHALLENGE {0}", fullUrl));\r
+                               }\r
+                               httpResponse.setHeader("WWW-Authenticate", CHALLENGE);\r
+                               httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);\r
+                               return;\r
+                       } else {\r
+                               // check user access for request\r
+                               if (user.canAdmin || canAccess(model, user, urlRequestType)) {\r
+                                       // authenticated request permitted.\r
+                                       // pass processing to the restricted servlet.\r
+                                       newSession(authenticatedRequest, httpResponse);\r
+                                       logger.info(MessageFormat.format("ARF: {0} ({1}) authenticated", fullUrl,\r
+                                                       HttpServletResponse.SC_CONTINUE));\r
+                                       chain.doFilter(authenticatedRequest, httpResponse);\r
+                                       return;\r
                                }\r
+                               // valid user, but not for requested access. send 403.\r
                                if (GitBlit.isDebugMode()) {\r
-                                       logger.info(MessageFormat\r
-                                                       .format("AUTH: invalid credentials ({0})", credentials));\r
+                                       logger.info(MessageFormat.format("ARF: {0} forbidden to access {1}",\r
+                                                       user.username, fullUrl));\r
                                }\r
+                               httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);\r
+                               return;\r
                        }\r
-\r
-                       // challenge client to provide credentials. send 401.\r
-                       if (GitBlit.isDebugMode()) {\r
-                               logger.info("ARF: " + fullUrl + " (" + HttpServletResponse.SC_UNAUTHORIZED + ")");\r
-                               logger.info("AUTH: Challenge " + CHALLENGE);\r
-                       }\r
-                       httpResponse.setHeader("WWW-Authenticate", CHALLENGE);\r
-                       httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);\r
-                       return;\r
                }\r
 \r
                if (GitBlit.isDebugMode()) {\r
-                       logger.info("ARF: " + fullUrl + " (" + HttpServletResponse.SC_CONTINUE\r
-                                       + ") unauthenticated");\r
+                       logger.info(MessageFormat.format("ARF: {0} ({1}) unauthenticated", fullUrl,\r
+                                       HttpServletResponse.SC_CONTINUE));\r
                }\r
                // unauthenticated request permitted.\r
                // pass processing to the restricted servlet.\r
-               chain.doFilter(accessRequest, httpResponse);\r
-       }\r
-\r
-       /**\r
-        * Taken from Jetty's LoginAuthenticator.renewSessionOnAuthentication()\r
-        */\r
-       protected void newSession(HttpServletRequest request, HttpServletResponse response) {\r
-               HttpSession oldSession = request.getSession(false);\r
-               if (oldSession != null && oldSession.getAttribute(SESSION_SECURED) == null) {\r
-                       synchronized (this) {\r
-                               Map<String, Object> attributes = new HashMap<String, Object>();\r
-                               Enumeration<String> e = oldSession.getAttributeNames();\r
-                               while (e.hasMoreElements()) {\r
-                                       String name = e.nextElement();\r
-                                       attributes.put(name, oldSession.getAttribute(name));\r
-                                       oldSession.removeAttribute(name);\r
-                               }\r
-                               oldSession.invalidate();\r
-\r
-                               HttpSession newSession = request.getSession(true);\r
-                               newSession.setAttribute(SESSION_SECURED, Boolean.TRUE);\r
-                               for (Map.Entry<String, Object> entry : attributes.entrySet()) {\r
-                                       newSession.setAttribute(entry.getKey(), entry.getValue());\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       /**\r
-        * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)\r
-        */\r
-       @Override\r
-       public void init(final FilterConfig config) throws ServletException {\r
-       }\r
-\r
-       /**\r
-        * @see javax.servlet.Filter#destroy()\r
-        */\r
-       @Override\r
-       public void destroy() {\r
-       }\r
-\r
-       /**\r
-        * Wraps a standard HttpServletRequest and overrides user principal methods.\r
-        */\r
-       public static class AccessRestrictionRequest extends ServletRequestWrapper {\r
-\r
-               private UserModel user;\r
-\r
-               public AccessRestrictionRequest(HttpServletRequest req) {\r
-                       super(req);\r
-                       user = new UserModel("anonymous");\r
-               }\r
-\r
-               void setUser(UserModel user) {\r
-                       this.user = user;\r
-               }\r
-\r
-               @Override\r
-               public String getRemoteUser() {\r
-                       return user.username;\r
-               }\r
-\r
-               @Override\r
-               public boolean isUserInRole(String role) {\r
-                       if (role.equals(Constants.ADMIN_ROLE)) {\r
-                               return user.canAdmin;\r
-                       }\r
-                       return user.canAccessRepository(role);\r
-               }\r
-\r
-               @Override\r
-               public Principal getUserPrincipal() {\r
-                       return user;\r
-               }\r
+               chain.doFilter(authenticatedRequest, httpResponse);\r
        }\r
 }
\ No newline at end of file
diff --git a/src/com/gitblit/AuthenticationFilter.java b/src/com/gitblit/AuthenticationFilter.java
new file mode 100644 (file)
index 0000000..6b7a0af
--- /dev/null
@@ -0,0 +1,201 @@
+/*\r
+ * Copyright 2011 gitblit.com.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.gitblit;\r
+\r
+import java.io.IOException;\r
+import java.nio.charset.Charset;\r
+import java.security.Principal;\r
+import java.text.MessageFormat;\r
+import java.util.Enumeration;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import javax.servlet.Filter;\r
+import javax.servlet.FilterChain;\r
+import javax.servlet.FilterConfig;\r
+import javax.servlet.ServletException;\r
+import javax.servlet.ServletRequest;\r
+import javax.servlet.ServletResponse;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+import javax.servlet.http.HttpSession;\r
+\r
+import org.eclipse.jgit.util.Base64;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import com.gitblit.models.UserModel;\r
+import com.gitblit.utils.StringUtils;\r
+\r
+/**\r
+ * The AuthenticationFilter is a servlet filter that preprocesses requests that\r
+ * match its url pattern definition in the web.xml file.\r
+ * \r
+ * http://en.wikipedia.org/wiki/Basic_access_authentication\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
+public abstract class AuthenticationFilter implements Filter {\r
+\r
+       protected static final String BASIC = "Basic";\r
+\r
+       protected static final String CHALLENGE = BASIC + " realm=\"" + Constants.NAME + "\"";\r
+\r
+       protected static final String SESSION_SECURED = "com.gitblit.secured";\r
+\r
+       protected transient Logger logger = LoggerFactory.getLogger(getClass());\r
+\r
+       /**\r
+        * doFilter does the actual work of preprocessing the request to ensure that\r
+        * the user may proceed.\r
+        * \r
+        * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,\r
+        *      javax.servlet.ServletResponse, javax.servlet.FilterChain)\r
+        */\r
+       @Override\r
+       public abstract void doFilter(final ServletRequest request, final ServletResponse response,\r
+                       final FilterChain chain) throws IOException, ServletException;\r
+\r
+       /**\r
+        * Returns the full relative url of the request.\r
+        * \r
+        * @param httpRequest\r
+        * @return url\r
+        */\r
+       protected String getFullUrl(HttpServletRequest httpRequest) {\r
+               String servletUrl = httpRequest.getContextPath() + httpRequest.getServletPath();\r
+               String url = httpRequest.getRequestURI().substring(servletUrl.length());\r
+               String params = httpRequest.getQueryString();\r
+               if (url.length() > 0 && url.charAt(0) == '/') {\r
+                       url = url.substring(1);\r
+               }\r
+               String fullUrl = url + (StringUtils.isEmpty(params) ? "" : ("?" + params));\r
+               return fullUrl;\r
+       }\r
+\r
+       /**\r
+        * Returns the user making the request, if the user has authenticated.\r
+        * \r
+        * @param httpRequest\r
+        * @return user\r
+        */\r
+       protected UserModel getUser(HttpServletRequest httpRequest) {\r
+               UserModel user = null;\r
+               // look for client authorization credentials in header\r
+               final String authorization = httpRequest.getHeader("Authorization");\r
+               if (authorization != null && authorization.startsWith(BASIC)) {\r
+                       // Authorization: Basic base64credentials\r
+                       String base64Credentials = authorization.substring(BASIC.length()).trim();\r
+                       String credentials = new String(Base64.decode(base64Credentials),\r
+                                       Charset.forName("UTF-8"));\r
+                       // credentials = username:password\r
+                       final String[] values = credentials.split(":");\r
+\r
+                       if (values.length == 2) {\r
+                               String username = values[0];\r
+                               char[] password = values[1].toCharArray();\r
+                               user = GitBlit.self().authenticate(username, password);\r
+                               if (user != null) {\r
+                                       return user;\r
+                               }\r
+                       }\r
+                       if (GitBlit.isDebugMode()) {\r
+                               logger.info(MessageFormat.format("AUTH: invalid credentials ({0})", credentials));\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+\r
+       /**\r
+        * Taken from Jetty's LoginAuthenticator.renewSessionOnAuthentication()\r
+        */\r
+       @SuppressWarnings("unchecked")\r
+       protected void newSession(HttpServletRequest request, HttpServletResponse response) {\r
+               HttpSession oldSession = request.getSession(false);\r
+               if (oldSession != null && oldSession.getAttribute(SESSION_SECURED) == null) {\r
+                       synchronized (this) {\r
+                               Map<String, Object> attributes = new HashMap<String, Object>();\r
+                               Enumeration<String> e = oldSession.getAttributeNames();\r
+                               while (e.hasMoreElements()) {\r
+                                       String name = e.nextElement();\r
+                                       attributes.put(name, oldSession.getAttribute(name));\r
+                                       oldSession.removeAttribute(name);\r
+                               }\r
+                               oldSession.invalidate();\r
+\r
+                               HttpSession newSession = request.getSession(true);\r
+                               newSession.setAttribute(SESSION_SECURED, Boolean.TRUE);\r
+                               for (Map.Entry<String, Object> entry : attributes.entrySet()) {\r
+                                       newSession.setAttribute(entry.getKey(), entry.getValue());\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)\r
+        */\r
+       @Override\r
+       public void init(final FilterConfig config) throws ServletException {\r
+       }\r
+\r
+       /**\r
+        * @see javax.servlet.Filter#destroy()\r
+        */\r
+       @Override\r
+       public void destroy() {\r
+       }\r
+\r
+       /**\r
+        * Wraps a standard HttpServletRequest and overrides user principal methods.\r
+        */\r
+       public static class AuthenticatedRequest extends ServletRequestWrapper {\r
+\r
+               private UserModel user;\r
+\r
+               public AuthenticatedRequest(HttpServletRequest req) {\r
+                       super(req);\r
+                       user = new UserModel("anonymous");\r
+               }\r
+               \r
+               UserModel getUser() {\r
+                       return user;\r
+               }\r
+\r
+               void setUser(UserModel user) {\r
+                       this.user = user;\r
+               }\r
+\r
+               @Override\r
+               public String getRemoteUser() {\r
+                       return user.username;\r
+               }\r
+\r
+               @Override\r
+               public boolean isUserInRole(String role) {\r
+                       if (role.equals(Constants.ADMIN_ROLE)) {\r
+                               return user.canAdmin;\r
+                       }\r
+                       return user.canAccessRepository(role);\r
+               }\r
+\r
+               @Override\r
+               public Principal getUserPrincipal() {\r
+                       return user;\r
+               }\r
+       }\r
+}
\ No newline at end of file
index 63a877f42eaabde5316a16992f332bdfd8156abd..3862a9db1e309eca2dd1e94177b811b96d2a74da 100644 (file)
@@ -213,6 +213,10 @@ public class Constants {
                        return LIST_REPOSITORIES;\r
                }\r
                \r
+               public boolean exceeds(RpcRequest type) {\r
+                       return this.ordinal() > type.ordinal();\r
+               }\r
+               \r
                @Override\r
                public String toString() {\r
                        return name();\r
diff --git a/src/com/gitblit/RpcFilter.java b/src/com/gitblit/RpcFilter.java
new file mode 100644 (file)
index 0000000..49df844
--- /dev/null
@@ -0,0 +1,131 @@
+/*\r
+ * Copyright 2011 gitblit.com.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.gitblit;\r
+\r
+import java.io.IOException;\r
+import java.text.MessageFormat;\r
+\r
+import javax.servlet.FilterChain;\r
+import javax.servlet.ServletException;\r
+import javax.servlet.ServletRequest;\r
+import javax.servlet.ServletResponse;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import com.gitblit.Constants.RpcRequest;\r
+import com.gitblit.models.UserModel;\r
+\r
+/**\r
+ * The RpcFilter is a servlet filter that secures the RpcServlet.\r
+ * \r
+ * The filter extracts the rpc request type from the url and determines if the\r
+ * requested action requires a Basic authentication prompt. If authentication is\r
+ * required and no credentials are stored in the "Authorization" header, then a\r
+ * basic authentication challenge is issued.\r
+ * \r
+ * http://en.wikipedia.org/wiki/Basic_access_authentication\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
+public class RpcFilter extends AuthenticationFilter {\r
+\r
+       /**\r
+        * doFilter does the actual work of preprocessing the request to ensure that\r
+        * the user may proceed.\r
+        * \r
+        * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,\r
+        *      javax.servlet.ServletResponse, javax.servlet.FilterChain)\r
+        */\r
+       @Override\r
+       public void doFilter(final ServletRequest request, final ServletResponse response,\r
+                       final FilterChain chain) throws IOException, ServletException {\r
+\r
+               HttpServletRequest httpRequest = (HttpServletRequest) request;\r
+               HttpServletResponse httpResponse = (HttpServletResponse) response;\r
+\r
+               if (!GitBlit.getBoolean(Keys.web.enableRpcServlet, false)) {\r
+                       logger.warn(Keys.web.enableRpcServlet + " must be set TRUE for rpc requests.");\r
+                       httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);\r
+                       return;\r
+               }\r
+\r
+               String fullUrl = getFullUrl(httpRequest);\r
+               RpcRequest requestType = RpcRequest.fromName(httpRequest.getParameter("req"));\r
+\r
+               boolean adminRequest = requestType.exceeds(RpcRequest.LIST_REPOSITORIES);\r
+\r
+               boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, false);\r
+               boolean authenticateAdmin = GitBlit.getBoolean(Keys.web.authenticateAdminPages, true);\r
+\r
+               // Wrap the HttpServletRequest with the RpcServletnRequest which\r
+               // overrides the servlet container user principal methods.\r
+               AuthenticatedRequest authenticatedRequest = new AuthenticatedRequest(httpRequest);\r
+               UserModel user = getUser(httpRequest);\r
+               if (user != null) {\r
+                       authenticatedRequest.setUser(user);\r
+               }\r
+               \r
+               // BASIC authentication challenge and response processing\r
+               if ((adminRequest && authenticateAdmin) || (!adminRequest && authenticateView)) {\r
+                       if (user == null) {\r
+                               // challenge client to provide credentials. send 401.\r
+                               if (GitBlit.isDebugMode()) {\r
+                                       logger.info(MessageFormat.format("RPC: CHALLENGE {0}", fullUrl));\r
+\r
+                               }\r
+                               httpResponse.setHeader("WWW-Authenticate", CHALLENGE);\r
+                               httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);\r
+                               return;\r
+                       } else {\r
+                               // check user access for request\r
+                               if (user.canAdmin || canAccess(user, requestType)) {\r
+                                       // authenticated request permitted.\r
+                                       // pass processing to the restricted servlet.\r
+                                       newSession(authenticatedRequest, httpResponse);\r
+                                       logger.info(MessageFormat.format("RPC: {0} ({1}) authenticated", fullUrl,\r
+                                                       HttpServletResponse.SC_CONTINUE));\r
+                                       chain.doFilter(authenticatedRequest, httpResponse);\r
+                                       return;\r
+                               }\r
+                               // valid user, but not for requested access. send 403.\r
+                               if (GitBlit.isDebugMode()) {\r
+                                       logger.info(MessageFormat.format("RPC: {0} forbidden to access {1}",\r
+                                                       user.username, fullUrl));\r
+                               }\r
+                               httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               if (GitBlit.isDebugMode()) {\r
+                       logger.info(MessageFormat.format("RPC: {0} ({1}) unauthenticated", fullUrl,\r
+                                       HttpServletResponse.SC_CONTINUE));\r
+               }\r
+               // unauthenticated request permitted.\r
+               // pass processing to the restricted servlet.\r
+               chain.doFilter(authenticatedRequest, httpResponse);\r
+       }\r
+\r
+       private boolean canAccess(UserModel user, RpcRequest requestType) {\r
+               switch (requestType) {\r
+               case LIST_REPOSITORIES:\r
+                       return true;\r
+               default:\r
+                       return user.canAdmin;\r
+               }\r
+       }\r
+}
\ No newline at end of file
index 83fd7337b2297521ddda3ad96209c619e573707b..9d26ee031bd3ba6eb8eec4b3739db662b4070f95 100644 (file)
  */\r
 package com.gitblit;\r
 \r
+import java.io.IOException;\r
 import java.text.MessageFormat;\r
 import java.util.ArrayList;\r
 import java.util.HashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
 \r
+import javax.servlet.ServletException;\r
+import javax.servlet.http.HttpServletRequest;\r
 import javax.servlet.http.HttpServletResponse;\r
 \r
 import com.gitblit.Constants.RpcRequest;\r
@@ -51,26 +54,16 @@ public class RpcServlet extends JsonServlet {
         * @throws java.io.IOException\r
         */\r
        @Override\r
-       protected void processRequest(javax.servlet.http.HttpServletRequest request,\r
-                       javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,\r
-                       java.io.IOException {\r
+       protected void processRequest(HttpServletRequest request, HttpServletResponse response)\r
+                       throws ServletException, IOException {\r
                RpcRequest reqType = RpcRequest.fromName(request.getParameter("req"));\r
                logger.info(MessageFormat.format("Rpc {0} request from {1}", reqType,\r
                                request.getRemoteAddr()));\r
 \r
-               if (!GitBlit.getBoolean(Keys.web.enableRpcServlet, false)) {\r
-                       logger.warn(Keys.web.enableRpcServlet + " must be set TRUE for rpc requests.");\r
-                       response.sendError(HttpServletResponse.SC_FORBIDDEN);\r
-                       return;\r
-               }\r
-\r
-               // TODO user authentication and authorization\r
-               UserModel user = null;\r
+               UserModel user = (UserModel) request.getUserPrincipal();\r
 \r
                Object result = null;\r
                if (RpcRequest.LIST_REPOSITORIES.equals(reqType)) {\r
-                       // list repositories\r
-\r
                        // Determine the Gitblit clone url\r
                        String gitblitUrl = HttpUtils.getGitblitURL(request);\r
                        StringBuilder sb = new StringBuilder();\r
@@ -79,6 +72,7 @@ public class RpcServlet extends JsonServlet {
                        sb.append("{0}");\r
                        String cloneUrl = sb.toString();\r
 \r
+                       // list repositories\r
                        List<RepositoryModel> list = GitBlit.self().getRepositoryModels(user);\r
                        Map<String, RepositoryModel> repositories = new HashMap<String, RepositoryModel>();\r
                        for (RepositoryModel model : list) {\r
@@ -88,11 +82,6 @@ public class RpcServlet extends JsonServlet {
                        result = repositories;\r
                } else if (RpcRequest.LIST_USERS.equals(reqType)) {\r
                        // list users\r
-                       if (user == null || !user.canAdmin) {\r
-                               response.sendError(HttpServletResponse.SC_FORBIDDEN);\r
-                               return;\r
-                       }\r
-                       // user is authorized to retrieve all accounts\r
                        List<String> names = GitBlit.self().getAllUsernames();\r
                        List<UserModel> users = new ArrayList<UserModel>();\r
                        for (String name : names) {\r