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 == null) {
68              return false;
69          }
70  
71          if (uri.endsWith("*.asmx")) {
72              return true;
73          }
74  
75          for (String prefix : _PREFIXES) {
76              if (uri.startsWith(prefix)) {
77                  return true;
78              }
79          }
80  
81          return false;
82      }
83  
84      protected User login(
85              HttpServletRequest request, HttpServletResponse response)
86          throws Exception {
87  
88          User user = null;
89  
90          // Get the Authorization header, if one was supplied
91  
92          String authorization = request.getHeader("Authorization");
93  
94          if (authorization == null) {
95              return user;
96          }
97  
98          StringTokenizer st = new StringTokenizer(authorization);
99  
100         if (!st.hasMoreTokens()) {
101             return user;
102         }
103 
104         String basic = st.nextToken();
105 
106         // We only handle HTTP Basic authentication
107 
108         if (!basic.equalsIgnoreCase(HttpServletRequest.BASIC_AUTH)) {
109             return user;
110         }
111 
112         String encodedCredentials = st.nextToken();
113 
114         if (_log.isDebugEnabled()) {
115             _log.debug("Encoded credentials are " + encodedCredentials);
116         }
117 
118         String decodedCredentials = new String(
119             Base64.decode(encodedCredentials));
120 
121         if (_log.isDebugEnabled()) {
122             _log.debug("Decoded credentials are " + decodedCredentials);
123         }
124 
125         int pos = decodedCredentials.indexOf(StringPool.COLON);
126 
127         if (pos == -1) {
128             return user;
129         }
130 
131         Company company = PortalUtil.getCompany(request);
132 
133         String login = GetterUtil.getString(
134             decodedCredentials.substring(0, pos));
135         long userId = GetterUtil.getLong(login);
136         String password = decodedCredentials.substring(pos + 1);
137 
138         Map<String, String[]> headerMap = new HashMap<String, String[]>();
139         Map<String, String[]> parameterMap = new HashMap<String, String[]>();
140 
141         int authResult = Authenticator.FAILURE;
142 
143         if (company.getAuthType().equals(CompanyConstants.AUTH_TYPE_EA)) {
144             authResult = UserLocalServiceUtil.authenticateByEmailAddress(
145                 company.getCompanyId(), login, password, headerMap,
146                 parameterMap);
147 
148             userId = UserLocalServiceUtil.getUserIdByEmailAddress(
149                 company.getCompanyId(), login);
150         }
151         else if (company.getAuthType().equals(CompanyConstants.AUTH_TYPE_SN)) {
152             authResult = UserLocalServiceUtil.authenticateByScreenName(
153                 company.getCompanyId(), login, password, headerMap,
154                 parameterMap);
155 
156             userId = UserLocalServiceUtil.getUserIdByScreenName(
157                 company.getCompanyId(), login);
158         }
159         else if (company.getAuthType().equals(CompanyConstants.AUTH_TYPE_ID)) {
160             authResult = UserLocalServiceUtil.authenticateByUserId(
161                 company.getCompanyId(), userId, password, headerMap,
162                 parameterMap);
163         }
164 
165         if (authResult == Authenticator.SUCCESS) {
166             user = UserLocalServiceUtil.getUser(userId);
167         }
168 
169         return user;
170     }
171 
172     protected void processFilter(
173             HttpServletRequest request, HttpServletResponse response,
174             FilterChain filterChain)
175         throws IOException, ServletException {
176 
177         String method = request.getMethod();
178 
179         String userAgent = GetterUtil.getString(
180             request.getHeader(HttpHeaders.USER_AGENT));
181 
182         if ((userAgent.startsWith(
183                 "Microsoft Data Access Internet Publishing") ||
184              userAgent.startsWith("Microsoft Office Protocol Discovery")) &&
185             method.equals(HttpMethods.OPTIONS)) {
186 
187             setOptionsHeaders(response);
188 
189             return;
190         }
191 
192         if (!isSharepointRequest(request.getRequestURI())) {
193             processFilter(
194                 SharepointFilter.class, request, response, filterChain);
195 
196             return;
197         }
198 
199         if (method.equals(HttpMethods.GET) || method.equals(HttpMethods.HEAD)) {
200             setGetHeaders(response);
201         }
202         else if (method.equals(HttpMethods.POST)) {
203             setPostHeaders(response);
204         }
205 
206         HttpSession session = request.getSession();
207 
208         User user = (User)session.getAttribute(WebKeys.USER);
209 
210         try {
211             if (user == null) {
212                 user = login(request, response);
213 
214                 if (user == null) {
215                     throw new PrincipalException("User is null");
216                 }
217 
218                 session.setAttribute(WebKeys.USER, user);
219             }
220 
221             PrincipalThreadLocal.setName(user.getUserId());
222 
223             PermissionChecker permissionChecker =
224                 PermissionCheckerFactoryUtil.create(user, false);
225 
226             PermissionThreadLocal.setPermissionChecker(permissionChecker);
227         }
228         catch (Exception e) {
229             sendUnauthorized(response);
230 
231             return;
232         }
233 
234         try {
235             processFilter(
236                 SharepointFilter.class, request, response, filterChain);
237         }
238         catch (Exception e) {
239             _log.error(e, e);
240         }
241     }
242 
243     protected void sendUnauthorized(HttpServletResponse response)
244         throws IOException {
245 
246         response.setHeader("WWW-Authenticate", "BASIC realm=\"Liferay\"");
247 
248         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
249 
250         response.flushBuffer();
251     }
252 
253     protected void setGetHeaders(HttpServletResponse response) {
254         response.setContentType("text/html");
255 
256         response.setHeader(
257             "Public-Extension", "http://schemas.microsoft.com/repl-2");
258         response.setHeader(
259             "MicrosoftSharePointTeamServices", SharepointUtil.VERSION);
260         response.setHeader("Cache-Control", "no-cache");
261     }
262 
263     protected void setOptionsHeaders(HttpServletResponse response) {
264         response.setHeader("MS-Author-Via", "MS-FP/4.0,DAV");
265         response.setHeader("MicrosoftOfficeWebServer", "5.0_Collab");
266         response.setHeader(
267             "MicrosoftSharePointTeamServices", SharepointUtil.VERSION);
268         response.setHeader("DAV", "1,2");
269         response.setHeader("Accept-Ranges", "none");
270         response.setHeader("Cache-Control", "no-cache");
271         response.setHeader(
272             "Allow",
273             "COPY, DELETE, GET, GETLIB, HEAD, LOCK, MKCOL, MOVE, OPTIONS, " +
274                 "POST, PROPFIND, PROPPATCH, PUT, UNLOCK");
275     }
276 
277     protected void setPostHeaders(HttpServletResponse response) {
278         response.setContentType("application/x-vermeer-rpc");
279 
280         response.setHeader(
281             "MicrosoftSharePointTeamServices", SharepointUtil.VERSION);
282         response.setHeader("Cache-Control", "no-cache");
283         response.setHeader("Connection", "close");
284     }
285 
286     private static final String[] _PREFIXES =
287         new String[] {
288             "/_vti_inf.html", "/_vti_bin", "/sharepoint", "/history",
289             "/resources"};
290 
291     private static Log _log = LogFactoryUtil.getLog(SharepointFilter.class);
292 
293 }