James Moger
2012-10-31 40b07bca7d02438cd0d660f3b1713ffa86f6df76
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.nio.charset.Charset;
20 import java.security.Principal;
21 import java.text.MessageFormat;
22 import java.util.Enumeration;
23 import java.util.HashMap;
24 import java.util.Map;
25
26 import javax.servlet.Filter;
27 import javax.servlet.FilterChain;
28 import javax.servlet.FilterConfig;
29 import javax.servlet.ServletException;
30 import javax.servlet.ServletRequest;
31 import javax.servlet.ServletResponse;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.servlet.http.HttpServletResponse;
34 import javax.servlet.http.HttpSession;
35
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import com.gitblit.models.UserModel;
773bb6 40 import com.gitblit.utils.Base64;
ca9d0f 41 import com.gitblit.utils.StringUtils;
JM 42
43 /**
44  * The AuthenticationFilter is a servlet filter that preprocesses requests that
45  * match its url pattern definition in the web.xml file.
46  * 
47  * http://en.wikipedia.org/wiki/Basic_access_authentication
48  * 
49  * @author James Moger
50  * 
51  */
52 public abstract class AuthenticationFilter implements Filter {
53
54     protected static final String BASIC = "Basic";
55
56     protected static final String CHALLENGE = BASIC + " realm=\"" + Constants.NAME + "\"";
57
58     protected static final String SESSION_SECURED = "com.gitblit.secured";
59
60     protected transient Logger logger = LoggerFactory.getLogger(getClass());
61
62     /**
63      * doFilter does the actual work of preprocessing the request to ensure that
64      * the user may proceed.
65      * 
66      * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
67      *      javax.servlet.ServletResponse, javax.servlet.FilterChain)
68      */
69     @Override
70     public abstract void doFilter(final ServletRequest request, final ServletResponse response,
71             final FilterChain chain) throws IOException, ServletException;
72
73     /**
74      * Returns the full relative url of the request.
75      * 
76      * @param httpRequest
77      * @return url
78      */
79     protected String getFullUrl(HttpServletRequest httpRequest) {
80         String servletUrl = httpRequest.getContextPath() + httpRequest.getServletPath();
81         String url = httpRequest.getRequestURI().substring(servletUrl.length());
82         String params = httpRequest.getQueryString();
83         if (url.length() > 0 && url.charAt(0) == '/') {
84             url = url.substring(1);
85         }
86         String fullUrl = url + (StringUtils.isEmpty(params) ? "" : ("?" + params));
87         return fullUrl;
88     }
89
90     /**
91      * Returns the user making the request, if the user has authenticated.
92      * 
93      * @param httpRequest
94      * @return user
95      */
96     protected UserModel getUser(HttpServletRequest httpRequest) {
97         UserModel user = null;
98         // look for client authorization credentials in header
99         final String authorization = httpRequest.getHeader("Authorization");
100         if (authorization != null && authorization.startsWith(BASIC)) {
101             // Authorization: Basic base64credentials
102             String base64Credentials = authorization.substring(BASIC.length()).trim();
103             String credentials = new String(Base64.decode(base64Credentials),
104                     Charset.forName("UTF-8"));
105             // credentials = username:password
2551e8 106             final String[] values = credentials.split(":",2);
ca9d0f 107
JM 108             if (values.length == 2) {
109                 String username = values[0];
110                 char[] password = values[1].toCharArray();
111                 user = GitBlit.self().authenticate(username, password);
112                 if (user != null) {
113                     return user;
114                 }
115             }
116             if (GitBlit.isDebugMode()) {
117                 logger.info(MessageFormat.format("AUTH: invalid credentials ({0})", credentials));
118             }
119         }
120         return null;
121     }
122
123     /**
124      * Taken from Jetty's LoginAuthenticator.renewSessionOnAuthentication()
125      */
126     @SuppressWarnings("unchecked")
127     protected void newSession(HttpServletRequest request, HttpServletResponse response) {
128         HttpSession oldSession = request.getSession(false);
129         if (oldSession != null && oldSession.getAttribute(SESSION_SECURED) == null) {
130             synchronized (this) {
131                 Map<String, Object> attributes = new HashMap<String, Object>();
132                 Enumeration<String> e = oldSession.getAttributeNames();
133                 while (e.hasMoreElements()) {
134                     String name = e.nextElement();
135                     attributes.put(name, oldSession.getAttribute(name));
136                     oldSession.removeAttribute(name);
137                 }
138                 oldSession.invalidate();
139
140                 HttpSession newSession = request.getSession(true);
141                 newSession.setAttribute(SESSION_SECURED, Boolean.TRUE);
142                 for (Map.Entry<String, Object> entry : attributes.entrySet()) {
143                     newSession.setAttribute(entry.getKey(), entry.getValue());
144                 }
145             }
146         }
147     }
148
149     /**
150      * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
151      */
152     @Override
153     public void init(final FilterConfig config) throws ServletException {
154     }
155
156     /**
157      * @see javax.servlet.Filter#destroy()
158      */
159     @Override
160     public void destroy() {
161     }
162
163     /**
164      * Wraps a standard HttpServletRequest and overrides user principal methods.
165      */
166     public static class AuthenticatedRequest extends ServletRequestWrapper {
167
168         private UserModel user;
169
170         public AuthenticatedRequest(HttpServletRequest req) {
171             super(req);
172             user = new UserModel("anonymous");
6adf56 173             user.isAuthenticated = false;
ca9d0f 174         }
efe8ec 175
ca9d0f 176         UserModel getUser() {
JM 177             return user;
178         }
179
180         void setUser(UserModel user) {
181             this.user = user;
182         }
183
184         @Override
185         public String getRemoteUser() {
186             return user.username;
187         }
188
189         @Override
190         public boolean isUserInRole(String role) {
191             if (role.equals(Constants.ADMIN_ROLE)) {
7f7051 192                 return user.canAdmin();
ca9d0f 193             }
efe8ec 194             // Gitblit does not currently use actual roles in the traditional
JM 195             // servlet container sense.  That is the reason this is marked
196             // deprecated, but I may want to revisit this.
ca9d0f 197             return user.canAccessRepository(role);
JM 198         }
199
200         @Override
201         public Principal getUserPrincipal() {
202             return user;
203         }
204     }
205 }