1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.servlet.filters.sso.opensso;
16  
17  import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.util.StringBundler;
21  import com.liferay.portal.kernel.util.StringPool;
22  import com.liferay.portal.kernel.util.StringUtil;
23  import com.liferay.portal.kernel.util.Validator;
24  import com.liferay.util.CookieUtil;
25  
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.InputStreamReader;
29  import java.io.OutputStreamWriter;
30  
31  import java.net.HttpURLConnection;
32  import java.net.MalformedURLException;
33  import java.net.URL;
34  
35  import java.util.ArrayList;
36  import java.util.HashMap;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.concurrent.ConcurrentHashMap;
40  
41  import javax.servlet.http.HttpServletRequest;
42  
43  /**
44   * <a href="OpenSSOUtil.java.html"><b><i>View Source</i></b></a>
45   *
46   * <p>
47   * See http://issues.liferay.com/browse/LEP-5943.
48   * </p>
49   *
50   * @author Prashant Dighe
51   * @author Brian Wing Shun Chan
52   * @author Wesley Gong
53   */
54  public class OpenSSOUtil {
55  
56      public static Map<String, String> getAttributes(
57          HttpServletRequest request, String serviceUrl) {
58  
59          return _instance._getAttributes(request, serviceUrl);
60      }
61  
62      public static String getSubjectId(
63          HttpServletRequest request, String serviceUrl) {
64  
65          return _instance._getSubjectId(request, serviceUrl);
66      }
67  
68      public static boolean isAuthenticated(
69              HttpServletRequest request, String serviceUrl)
70          throws IOException {
71  
72          return _instance._isAuthenticated(request, serviceUrl);
73      }
74  
75      public static boolean isValidServiceUrl(String serviceUrl) {
76          return _instance._isValidServiceUrl(serviceUrl);
77      }
78  
79      public static boolean isValidUrl(String url) {
80          return _instance._isValidUrl(url);
81      }
82  
83      public static boolean isValidUrls(String[] urls) {
84          return _instance._isValidUrls(urls);
85      }
86  
87      private OpenSSOUtil() {
88      }
89  
90      private Map<String, String> _getAttributes(
91          HttpServletRequest request, String serviceUrl) {
92  
93          Map<String, String> nameValues = new HashMap<String, String>();
94  
95          String url = serviceUrl + _GET_ATTRIBUTES;
96  
97          try {
98              URL urlObj = new URL(url);
99  
100             HttpURLConnection urlc = (HttpURLConnection)urlObj.openConnection();
101 
102             urlc.setDoOutput(true);
103             urlc.setRequestMethod("POST");
104             urlc.setRequestProperty(
105                 "Content-type", "application/x-www-form-urlencoded");
106 
107             String[] cookieNames = _getCookieNames(serviceUrl);
108 
109             _setCookieProperty(request, urlc, cookieNames);
110 
111             OutputStreamWriter osw = new OutputStreamWriter(
112                 urlc.getOutputStream());
113 
114             osw.write("dummy");
115 
116             osw.flush();
117 
118             int responseCode = urlc.getResponseCode();
119 
120             if (responseCode == HttpURLConnection.HTTP_OK) {
121                 UnsyncBufferedReader unsyncBufferedReader =
122                     new UnsyncBufferedReader(
123                         new InputStreamReader((InputStream)urlc.getContent()));
124 
125                 String line = null;
126 
127                 while ((line = unsyncBufferedReader.readLine()) != null) {
128                     if (line.startsWith("userdetails.attribute.name=")) {
129                         String name = line.replaceFirst(
130                             "userdetails.attribute.name=", "");
131 
132                         line = unsyncBufferedReader.readLine();
133 
134                         if (line.startsWith("userdetails.attribute.value=")) {
135                             String value = line.replaceFirst(
136                                 "userdetails.attribute.value=", "");
137 
138                             nameValues.put(name, value);
139                         }
140                     }
141                 }
142             }
143             else if (_log.isDebugEnabled()) {
144                 _log.debug("Attributes response code " + responseCode);
145             }
146         }
147         catch (MalformedURLException mfue) {
148             _log.error(mfue.getMessage());
149 
150             if (_log.isDebugEnabled()) {
151                 _log.debug(mfue, mfue);
152             }
153         }
154         catch (IOException ioe) {
155             _log.error(ioe.getMessage());
156 
157             if (_log.isDebugEnabled()) {
158                 _log.debug(ioe, ioe);
159             }
160         }
161 
162         return nameValues;
163     }
164 
165     private String[] _getCookieNames(String serviceUrl) {
166         String[] cookieNames = _cookieNamesMap.get(serviceUrl);
167 
168         if (cookieNames != null) {
169             return cookieNames;
170         }
171 
172         List<String> cookieNamesList = new ArrayList<String>();
173 
174         try {
175             String cookieName = null;
176 
177             String url = serviceUrl + _GET_COOKIE_NAME;
178 
179             URL urlObj = new URL(url);
180 
181             HttpURLConnection urlc = (HttpURLConnection)urlObj.openConnection();
182 
183             UnsyncBufferedReader unsyncBufferedReader =
184                 new UnsyncBufferedReader(
185                     new InputStreamReader((InputStream)urlc.getContent()));
186 
187             int responseCode = urlc.getResponseCode();
188 
189             if (responseCode != HttpURLConnection.HTTP_OK) {
190                 if (_log.isDebugEnabled()) {
191                     _log.debug(url + " has response code " + responseCode);
192                 }
193             }
194             else {
195                 String line = null;
196 
197                 while ((line = unsyncBufferedReader.readLine()) != null) {
198                     if (line.startsWith("string=")) {
199                         line = line.replaceFirst("string=", "");
200 
201                         cookieName = line;
202                     }
203                 }
204             }
205 
206             url = serviceUrl + _GET_COOKIE_NAMES;
207 
208             urlObj = new URL(url);
209 
210             urlc = (HttpURLConnection)urlObj.openConnection();
211 
212             unsyncBufferedReader = new UnsyncBufferedReader(
213                 new InputStreamReader((InputStream)urlc.getContent()));
214 
215             if (urlc.getResponseCode() != HttpURLConnection.HTTP_OK) {
216                 if (_log.isDebugEnabled()) {
217                     _log.debug(url + " has response code " + responseCode);
218                 }
219             }
220             else {
221                 String line = null;
222 
223                 while ((line = unsyncBufferedReader.readLine()) != null) {
224                     if (line.startsWith("string=")) {
225                         line = line.replaceFirst("string=", "");
226 
227                         if (cookieName.equals(line)) {
228                             cookieNamesList.add(0, cookieName);
229                         }
230                         else {
231                             cookieNamesList.add(line);
232                         }
233                     }
234                 }
235             }
236         }
237         catch (IOException ioe) {
238             if (_log.isWarnEnabled()) {
239                 _log.warn(ioe, ioe);
240             }
241         }
242 
243         cookieNames = cookieNamesList.toArray(
244             new String[cookieNamesList.size()]);
245 
246         if (cookieNames.length > 0) {
247             _cookieNamesMap.put(serviceUrl, cookieNames);
248         }
249 
250         return cookieNames;
251     }
252 
253     private String _getSubjectId(
254         HttpServletRequest request, String serviceUrl) {
255 
256         String cookieName = _getCookieNames(serviceUrl)[0];
257 
258         return CookieUtil.get(request, cookieName);
259     }
260 
261     private boolean _isAuthenticated(
262             HttpServletRequest request, String serviceUrl)
263         throws IOException {
264 
265         boolean authenticated = false;
266 
267         String url = serviceUrl + _VALIDATE_TOKEN;
268 
269         URL urlObj = new URL(url);
270 
271         HttpURLConnection urlc = (HttpURLConnection)urlObj.openConnection();
272 
273         urlc.setDoOutput(true);
274         urlc.setRequestMethod("POST");
275         urlc.setRequestProperty(
276             "Content-type", "application/x-www-form-urlencoded");
277 
278         String[] cookieNames = _getCookieNames(serviceUrl);
279 
280         if (cookieNames.length == 0) {
281             throw new IOException(
282                 "Cookie names from OpenSSO service are not accessible");
283         }
284 
285         _setCookieProperty(request, urlc, cookieNames);
286 
287         OutputStreamWriter osw = new OutputStreamWriter(urlc.getOutputStream());
288 
289         osw.write("dummy");
290 
291         osw.flush();
292 
293         int responseCode = urlc.getResponseCode();
294 
295         if (responseCode == HttpURLConnection.HTTP_OK) {
296             String data = StringUtil.read(urlc.getInputStream());
297 
298             if (data.toLowerCase().indexOf("boolean=true") != -1) {
299                 authenticated = true;
300             }
301         }
302         else if (_log.isDebugEnabled()) {
303             _log.debug("Authentication response code " + responseCode);
304         }
305 
306         return authenticated;
307     }
308 
309     private boolean _isValidServiceUrl(String serviceUrl) {
310         if (Validator.isNull(serviceUrl)) {
311             return false;
312         }
313 
314         String[] cookieNames = _instance._getCookieNames(serviceUrl);
315 
316         if (cookieNames.length == 0) {
317             return false;
318         }
319 
320         return true;
321     }
322 
323     private boolean _isValidUrl(String url) {
324         if (Validator.isNull(url)) {
325             return false;
326         }
327 
328         try {
329             URL urlObj = new URL(url);
330 
331             HttpURLConnection urlc = (HttpURLConnection)urlObj.openConnection();
332 
333             int responseCode = urlc.getResponseCode();
334 
335             if (responseCode != HttpURLConnection.HTTP_OK) {
336                 if (_log.isDebugEnabled()) {
337                     _log.debug("Attributes response code " + responseCode);
338                 }
339 
340                 return false;
341             }
342         }
343         catch (IOException ioe) {
344             if (_log.isWarnEnabled()) {
345                 _log.warn(ioe, ioe);
346             }
347 
348             return false;
349         }
350 
351         return true;
352     }
353 
354     private boolean _isValidUrls(String[] urls) {
355         for (String url : urls) {
356             if (!_isValidUrl(url)) {
357                 return false;
358             }
359         }
360 
361         return true;
362     }
363 
364     private void _setCookieProperty(
365         HttpServletRequest request, HttpURLConnection urlc,
366         String[] cookieNames) {
367 
368         if (cookieNames.length == 0) {
369             return;
370         }
371 
372         StringBundler sb = new StringBundler(cookieNames.length * 4);
373 
374         for (String cookieName : cookieNames) {
375             String cookieValue = CookieUtil.get(request, cookieName);
376 
377             sb.append(cookieName);
378             sb.append(StringPool.EQUAL);
379             sb.append(StringPool.QUOTE);
380             sb.append(cookieValue);
381             sb.append(StringPool.QUOTE);
382             sb.append(StringPool.SEMICOLON);
383         }
384 
385         urlc.setRequestProperty("Cookie", sb.toString());
386     }
387 
388     private static final String _GET_ATTRIBUTES = "/identity/attributes";
389 
390     private static final String _GET_COOKIE_NAME =
391         "/identity/getCookieNameForToken";
392 
393     private static final String _GET_COOKIE_NAMES =
394         "/identity/getCookieNamesToForward";
395 
396     private static final String _VALIDATE_TOKEN = "/identity/isTokenValid";
397 
398     private static Log _log = LogFactoryUtil.getLog(OpenSSOUtil.class);
399 
400     private static OpenSSOUtil _instance = new OpenSSOUtil();
401 
402     private Map<String, String[]> _cookieNamesMap =
403         new ConcurrentHashMap<String, String[]>();
404 
405 }