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.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.eclipse.jgit.util.Base64;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 import com.gitblit.models.UserModel;
41 import com.gitblit.utils.StringUtils;
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
106             final String[] values = credentials.split(":");
107
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");
173         }
174         
175         UserModel getUser() {
176             return user;
177         }
178
179         void setUser(UserModel user) {
180             this.user = user;
181         }
182
183         @Override
184         public String getRemoteUser() {
185             return user.username;
186         }
187
188         @Override
189         public boolean isUserInRole(String role) {
190             if (role.equals(Constants.ADMIN_ROLE)) {
191                 return user.canAdmin;
192             }
193             return user.canAccessRepository(role);
194         }
195
196         @Override
197         public Principal getUserPrincipal() {
198             return user;
199         }
200     }
201 }