1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.sharepoint;
24  
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  import com.liferay.portal.kernel.servlet.HttpHeaders;
28  import com.liferay.portal.kernel.servlet.HttpMethods;
29  import com.liferay.portal.kernel.util.Base64;
30  import com.liferay.portal.kernel.util.GetterUtil;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.model.Company;
33  import com.liferay.portal.model.CompanyConstants;
34  import com.liferay.portal.model.User;
35  import com.liferay.portal.security.auth.Authenticator;
36  import com.liferay.portal.security.auth.PrincipalException;
37  import com.liferay.portal.security.auth.PrincipalThreadLocal;
38  import com.liferay.portal.security.permission.PermissionChecker;
39  import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
40  import com.liferay.portal.security.permission.PermissionThreadLocal;
41  import com.liferay.portal.service.UserLocalServiceUtil;
42  import com.liferay.portal.servlet.filters.BasePortalFilter;
43  import com.liferay.portal.util.PortalUtil;
44  import com.liferay.portal.util.WebKeys;
45  
46  import java.io.IOException;
47  
48  import java.util.HashMap;
49  import java.util.Map;
50  import java.util.StringTokenizer;
51  
52  import javax.servlet.FilterChain;
53  import javax.servlet.ServletException;
54  import javax.servlet.http.HttpServletRequest;
55  import javax.servlet.http.HttpServletResponse;
56  import javax.servlet.http.HttpSession;
57  
58  /**
59   * <a href="SharepointFilter.java.html"><b><i>View Source</i></b></a>
60   *
61   * @author Bruno Farache
62   *
63   */
64  public class SharepointFilter extends BasePortalFilter {
65  
66      protected boolean isSharepointRequest(String uri) {
67          if (uri.endsWith("*.asmx")) {
68              return true;
69          }
70  
71          for (String prefix : _PREFIXES) {
72              if (uri.startsWith(prefix)) {
73                  return true;
74              }
75          }
76  
77          return false;
78      }
79  
80      protected User login(
81              HttpServletRequest request, HttpServletResponse response)
82          throws Exception {
83  
84          User user = null;
85  
86          // Get the Authorization header, if one was supplied
87  
88          String authorization = request.getHeader("Authorization");
89  
90          if (authorization == null) {
91              return user;
92          }
93  
94          StringTokenizer st = new StringTokenizer(authorization);
95  
96          if (!st.hasMoreTokens()) {
97              return user;
98          }
99  
100         String basic = st.nextToken();
101 
102         // We only handle HTTP Basic authentication
103 
104         if (!basic.equalsIgnoreCase(HttpServletRequest.BASIC_AUTH)) {
105             return user;
106         }
107 
108         String encodedCredentials = st.nextToken();
109 
110         if (_log.isDebugEnabled()) {
111             _log.debug("Encoded credentials are " + encodedCredentials);
112         }
113 
114         String decodedCredentials = new String(
115             Base64.decode(encodedCredentials));
116 
117         if (_log.isDebugEnabled()) {
118             _log.debug("Decoded credentials are " + decodedCredentials);
119         }
120 
121         int pos = decodedCredentials.indexOf(StringPool.COLON);
122 
123         if (pos == -1) {
124             return user;
125         }
126 
127         Company company = PortalUtil.getCompany(request);
128 
129         String login = GetterUtil.getString(
130             decodedCredentials.substring(0, pos));
131         long userId = GetterUtil.getLong(login);
132         String password = decodedCredentials.substring(pos + 1);
133 
134         Map<String, String[]> headerMap = new HashMap<String, String[]>();
135         Map<String, String[]> parameterMap = new HashMap<String, String[]>();
136 
137         int authResult = Authenticator.FAILURE;
138 
139         if (company.getAuthType().equals(CompanyConstants.AUTH_TYPE_EA)) {
140             authResult = UserLocalServiceUtil.authenticateByEmailAddress(
141                 company.getCompanyId(), login, password, headerMap,
142                 parameterMap);
143 
144             userId = UserLocalServiceUtil.getUserIdByEmailAddress(
145                 company.getCompanyId(), login);
146         }
147         else if (company.getAuthType().equals(CompanyConstants.AUTH_TYPE_SN)) {
148             authResult = UserLocalServiceUtil.authenticateByScreenName(
149                 company.getCompanyId(), login, password, headerMap,
150                 parameterMap);
151 
152             userId = UserLocalServiceUtil.getUserIdByScreenName(
153                 company.getCompanyId(), login);
154         }
155         else if (company.getAuthType().equals(CompanyConstants.AUTH_TYPE_ID)) {
156             authResult = UserLocalServiceUtil.authenticateByUserId(
157                 company.getCompanyId(), userId, password, headerMap,
158                 parameterMap);
159         }
160 
161         if (authResult == Authenticator.SUCCESS) {
162             user = UserLocalServiceUtil.getUser(userId);
163         }
164 
165         return user;
166     }
167 
168     protected void processFilter(
169             HttpServletRequest request, HttpServletResponse response,
170             FilterChain filterChain)
171         throws IOException, ServletException {
172 
173         String method = request.getMethod();
174 
175         String userAgent = request.getHeader(HttpHeaders.USER_AGENT);
176 
177         if ((userAgent.startsWith(
178                 "Microsoft Data Access Internet Publishing") ||
179              userAgent.startsWith("Microsoft Office Protocol Discovery")) &&
180             method.equals(HttpMethods.OPTIONS)) {
181 
182             setOptionsHeaders(response);
183 
184             return;
185         }
186 
187         if (!isSharepointRequest(request.getRequestURI())) {
188             processFilter(
189                 SharepointFilter.class, request, response, filterChain);
190 
191             return;
192         }
193 
194         if (method.equals(HttpMethods.GET) || method.equals(HttpMethods.HEAD)) {
195             setGetHeaders(response);
196         }
197         else if (method.equals(HttpMethods.POST)) {
198             setPostHeaders(response);
199         }
200 
201         HttpSession session = request.getSession();
202 
203         User user = (User)session.getAttribute(WebKeys.USER);
204 
205         try {
206             if (user == null) {
207                 user = login(request, response);
208 
209                 if (user == null) {
210                     throw new PrincipalException("User is null");
211                 }
212 
213                 session.setAttribute(WebKeys.USER, user);
214             }
215 
216             PrincipalThreadLocal.setName(user.getUserId());
217 
218             PermissionChecker permissionChecker =
219                 PermissionCheckerFactoryUtil.create(user, false);
220 
221             PermissionThreadLocal.setPermissionChecker(permissionChecker);
222         }
223         catch (Exception e) {
224             sendUnauthorized(response);
225 
226             return;
227         }
228 
229         try {
230             processFilter(
231                 SharepointFilter.class, request, response, filterChain);
232         }
233         catch (Exception e) {
234             _log.error(e, e);
235         }
236     }
237 
238     protected void sendUnauthorized(HttpServletResponse response)
239         throws IOException {
240 
241         response.setHeader("WWW-Authenticate", "BASIC realm=\"Liferay\"");
242 
243         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
244 
245         response.flushBuffer();
246     }
247 
248     protected void setGetHeaders(HttpServletResponse response) {
249         response.setContentType("text/html");
250 
251         response.setHeader(
252             "Public-Extension", "http://schemas.microsoft.com/repl-2");
253         response.setHeader(
254             "MicrosoftSharePointTeamServices", SharepointUtil.VERSION);
255         response.setHeader("Cache-Control", "no-cache");
256     }
257 
258     protected void setOptionsHeaders(HttpServletResponse response) {
259         response.setHeader("MS-Author-Via", "MS-FP/4.0,DAV");
260         response.setHeader("MicrosoftOfficeWebServer", "5.0_Collab");
261         response.setHeader(
262             "MicrosoftSharePointTeamServices", SharepointUtil.VERSION);
263         response.setHeader("DAV", "1,2");
264         response.setHeader("Accept-Ranges", "none");
265         response.setHeader("Cache-Control", "no-cache");
266         response.setHeader(
267             "Allow",
268             "COPY, DELETE, GET, GETLIB, HEAD, LOCK, MKCOL, MOVE, OPTIONS, " +
269                 "POST, PROPFIND, PROPPATCH, PUT, UNLOCK");
270     }
271 
272     protected void setPostHeaders(HttpServletResponse response) {
273         response.setContentType("application/x-vermeer-rpc");
274 
275         response.setHeader(
276             "MicrosoftSharePointTeamServices", SharepointUtil.VERSION);
277         response.setHeader("Cache-Control", "no-cache");
278         response.setHeader("Connection", "close");
279     }
280 
281     private static final String[] _PREFIXES =
282         new String[] {
283             "/_vti_inf.html", "/_vti_bin", "/sharepoint", "/history",
284             "/resources"};
285 
286     private static Log _log = LogFactoryUtil.getLog(SharepointFilter.class);
287 
288 }