001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.servlet.filters.sso.opensso;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.util.CookieKeys;
021    import com.liferay.portal.kernel.util.StringBundler;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.kernel.util.Validator;
025    
026    import java.io.IOException;
027    import java.io.InputStream;
028    import java.io.InputStreamReader;
029    import java.io.OutputStreamWriter;
030    
031    import java.net.HttpURLConnection;
032    import java.net.MalformedURLException;
033    import java.net.URL;
034    
035    import java.util.ArrayList;
036    import java.util.HashMap;
037    import java.util.List;
038    import java.util.Map;
039    import java.util.concurrent.ConcurrentHashMap;
040    
041    import javax.servlet.http.HttpServletRequest;
042    
043    /**
044     * <p>
045     * See http://issues.liferay.com/browse/LEP-5943.
046     * </p>
047     *
048     * @author Prashant Dighe
049     * @author Brian Wing Shun Chan
050     * @author Wesley Gong
051     */
052    public class OpenSSOUtil {
053    
054            public static Map<String, String> getAttributes(
055                    HttpServletRequest request, String serviceUrl) {
056    
057                    return _instance._getAttributes(request, serviceUrl);
058            }
059    
060            public static String getSubjectId(
061                    HttpServletRequest request, String serviceUrl) {
062    
063                    return _instance._getSubjectId(request, serviceUrl);
064            }
065    
066            public static boolean isAuthenticated(
067                            HttpServletRequest request, String serviceUrl)
068                    throws IOException {
069    
070                    return _instance._isAuthenticated(request, serviceUrl);
071            }
072    
073            public static boolean isValidServiceUrl(String serviceUrl) {
074                    return _instance._isValidServiceUrl(serviceUrl);
075            }
076    
077            public static boolean isValidUrl(String url) {
078                    return _instance._isValidUrl(url);
079            }
080    
081            public static boolean isValidUrls(String[] urls) {
082                    return _instance._isValidUrls(urls);
083            }
084    
085            private OpenSSOUtil() {
086            }
087    
088            private Map<String, String> _getAttributes(
089                    HttpServletRequest request, String serviceUrl) {
090    
091                    Map<String, String> nameValues = new HashMap<String, String>();
092    
093                    String url = serviceUrl.concat(_GET_ATTRIBUTES);
094    
095                    try {
096                            URL urlObj = new URL(url);
097    
098                            HttpURLConnection httpURLConnection =
099                                    (HttpURLConnection)urlObj.openConnection();
100    
101                            httpURLConnection.setDoOutput(true);
102                            httpURLConnection.setRequestMethod("POST");
103                            httpURLConnection.setRequestProperty(
104                                    "Content-type", "application/x-www-form-urlencoded");
105    
106                            String[] cookieNames = _getCookieNames(serviceUrl);
107    
108                            _setCookieProperty(request, httpURLConnection, cookieNames);
109    
110                            OutputStreamWriter osw = new OutputStreamWriter(
111                                    httpURLConnection.getOutputStream());
112    
113                            osw.write("dummy");
114    
115                            osw.flush();
116    
117                            int responseCode = httpURLConnection.getResponseCode();
118    
119                            if (responseCode == HttpURLConnection.HTTP_OK) {
120                                    InputStream inputStream =
121                                            (InputStream)httpURLConnection.getContent();
122    
123                                    UnsyncBufferedReader unsyncBufferedReader =
124                                            new UnsyncBufferedReader(
125                                                    new InputStreamReader(inputStream));
126    
127                                    String line = null;
128    
129                                    while ((line = unsyncBufferedReader.readLine()) != null) {
130                                            if (line.startsWith("userdetails.attribute.name=")) {
131                                                    String name = line.replaceFirst(
132                                                            "userdetails.attribute.name=", "");
133    
134                                                    line = unsyncBufferedReader.readLine();
135    
136                                                    if (line.startsWith("userdetails.attribute.value=")) {
137                                                            String value = line.replaceFirst(
138                                                                    "userdetails.attribute.value=", "");
139    
140                                                            nameValues.put(name, value);
141                                                    }
142                                            }
143                                    }
144                            }
145                            else if (_log.isDebugEnabled()) {
146                                    _log.debug("Attributes response code " + responseCode);
147                            }
148                    }
149                    catch (MalformedURLException murle) {
150                            _log.error(murle.getMessage());
151    
152                            if (_log.isDebugEnabled()) {
153                                    _log.debug(murle, murle);
154                            }
155                    }
156                    catch (IOException ioe) {
157                            _log.error(ioe.getMessage());
158    
159                            if (_log.isDebugEnabled()) {
160                                    _log.debug(ioe, ioe);
161                            }
162                    }
163    
164                    return nameValues;
165            }
166    
167            private String[] _getCookieNames(String serviceUrl) {
168                    String[] cookieNames = _cookieNamesMap.get(serviceUrl);
169    
170                    if (cookieNames != null) {
171                            return cookieNames;
172                    }
173    
174                    List<String> cookieNamesList = new ArrayList<String>();
175    
176                    try {
177                            String cookieName = null;
178    
179                            String url = serviceUrl.concat(_GET_COOKIE_NAME);
180    
181                            URL urlObj = new URL(url);
182    
183                            HttpURLConnection httpURLConnection =
184                                    (HttpURLConnection)urlObj.openConnection();
185    
186                            InputStream inputStream =
187                                    (InputStream)httpURLConnection.getContent();
188    
189                            UnsyncBufferedReader unsyncBufferedReader =
190                                    new UnsyncBufferedReader(new InputStreamReader(inputStream));
191    
192                            int responseCode = httpURLConnection.getResponseCode();
193    
194                            if (responseCode != HttpURLConnection.HTTP_OK) {
195                                    if (_log.isDebugEnabled()) {
196                                            _log.debug(url + " has response code " + responseCode);
197                                    }
198                            }
199                            else {
200                                    String line = null;
201    
202                                    while ((line = unsyncBufferedReader.readLine()) != null) {
203                                            if (line.startsWith("string=")) {
204                                                    line = line.replaceFirst("string=", "");
205    
206                                                    cookieName = line;
207                                            }
208                                    }
209                            }
210    
211                            url = serviceUrl.concat(_GET_COOKIE_NAMES);
212    
213                            urlObj = new URL(url);
214    
215                            httpURLConnection = (HttpURLConnection)urlObj.openConnection();
216    
217                            inputStream = (InputStream)httpURLConnection.getContent();
218    
219                            unsyncBufferedReader = new UnsyncBufferedReader(
220                                    new InputStreamReader(inputStream));
221    
222                            if (httpURLConnection.getResponseCode() !=
223                                            HttpURLConnection.HTTP_OK) {
224    
225                                    if (_log.isDebugEnabled()) {
226                                            _log.debug(url + " has response code " + responseCode);
227                                    }
228                            }
229                            else {
230                                    String line = null;
231    
232                                    while ((line = unsyncBufferedReader.readLine()) != null) {
233                                            if (line.startsWith("string=")) {
234                                                    line = line.replaceFirst("string=", "");
235    
236                                                    if (cookieName.equals(line)) {
237                                                            cookieNamesList.add(0, cookieName);
238                                                    }
239                                                    else {
240                                                            cookieNamesList.add(line);
241                                                    }
242                                            }
243                                    }
244                            }
245                    }
246                    catch (IOException ioe) {
247                            if (_log.isWarnEnabled()) {
248                                    _log.warn(ioe, ioe);
249                            }
250                    }
251    
252                    cookieNames = cookieNamesList.toArray(
253                            new String[cookieNamesList.size()]);
254    
255                    if (cookieNames.length > 0) {
256                            _cookieNamesMap.put(serviceUrl, cookieNames);
257                    }
258    
259                    return cookieNames;
260            }
261    
262            private String _getSubjectId(
263                    HttpServletRequest request, String serviceUrl) {
264    
265                    String cookieName = _getCookieNames(serviceUrl)[0];
266    
267                    return CookieKeys.getCookie(request, cookieName);
268            }
269    
270            private boolean _isAuthenticated(
271                            HttpServletRequest request, String serviceUrl)
272                    throws IOException {
273    
274                    boolean authenticated = false;
275    
276                    boolean hasCookieNames = false;
277    
278                    String[] cookieNames = _getCookieNames(serviceUrl);
279    
280                    for (String cookieName : cookieNames) {
281                            if (CookieKeys.getCookie(request, cookieName) != null) {
282                                    hasCookieNames = true;
283    
284                                    break;
285                            }
286                    }
287    
288                    if (!hasCookieNames) {
289                            if (_log.isWarnEnabled()) {
290                                    _log.warn(
291                                            "User is not logged in because he has no OpenSSO cookies");
292                            }
293    
294                            return false;
295                    }
296    
297                    String url = serviceUrl.concat(_VALIDATE_TOKEN);
298    
299                    URL urlObj = new URL(url);
300    
301                    HttpURLConnection httpURLConnection =
302                            (HttpURLConnection)urlObj.openConnection();
303    
304                    httpURLConnection.setDoOutput(true);
305                    httpURLConnection.setRequestMethod("POST");
306                    httpURLConnection.setRequestProperty(
307                            "Content-type", "application/x-www-form-urlencoded");
308    
309                    _setCookieProperty(request, httpURLConnection, cookieNames);
310    
311                    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
312                            httpURLConnection.getOutputStream());
313    
314                    outputStreamWriter.write("dummy");
315    
316                    outputStreamWriter.flush();
317    
318                    int responseCode = httpURLConnection.getResponseCode();
319    
320                    if (responseCode == HttpURLConnection.HTTP_OK) {
321                            String data = StringUtil.read(httpURLConnection.getInputStream());
322    
323                            if (StringUtil.toLowerCase(data).contains("boolean=true")) {
324                                    authenticated = true;
325                            }
326                    }
327                    else if (_log.isDebugEnabled()) {
328                            _log.debug("Authentication response code " + responseCode);
329                    }
330    
331                    return authenticated;
332            }
333    
334            private boolean _isValidServiceUrl(String serviceUrl) {
335                    if (Validator.isNull(serviceUrl)) {
336                            return false;
337                    }
338    
339                    String[] cookieNames = _instance._getCookieNames(serviceUrl);
340    
341                    if (cookieNames.length == 0) {
342                            return false;
343                    }
344    
345                    return true;
346            }
347    
348            private boolean _isValidUrl(String url) {
349                    if (Validator.isNull(url)) {
350                            return false;
351                    }
352    
353                    try {
354                            URL urlObj = new URL(url);
355    
356                            HttpURLConnection httpURLConnection =
357                                    (HttpURLConnection)urlObj.openConnection();
358    
359                            int responseCode = httpURLConnection.getResponseCode();
360    
361                            if (responseCode != HttpURLConnection.HTTP_OK) {
362                                    if (_log.isDebugEnabled()) {
363                                            _log.debug("Attributes response code " + responseCode);
364                                    }
365    
366                                    return false;
367                            }
368                    }
369                    catch (IOException ioe) {
370                            if (_log.isWarnEnabled()) {
371                                    _log.warn(ioe, ioe);
372                            }
373    
374                            return false;
375                    }
376    
377                    return true;
378            }
379    
380            private boolean _isValidUrls(String[] urls) {
381                    for (String url : urls) {
382                            if (!_isValidUrl(url)) {
383                                    return false;
384                            }
385                    }
386    
387                    return true;
388            }
389    
390            private void _setCookieProperty(
391                    HttpServletRequest request, HttpURLConnection urlc,
392                    String[] cookieNames) {
393    
394                    if (cookieNames.length == 0) {
395                            return;
396                    }
397    
398                    StringBundler sb = new StringBundler(cookieNames.length * 4);
399    
400                    for (String cookieName : cookieNames) {
401                            String cookieValue = CookieKeys.getCookie(request, cookieName);
402    
403                            sb.append(cookieName);
404                            sb.append(StringPool.EQUAL);
405                            sb.append(StringPool.QUOTE);
406                            sb.append(cookieValue);
407                            sb.append(StringPool.QUOTE);
408                            sb.append(StringPool.SEMICOLON);
409                    }
410    
411                    urlc.setRequestProperty("Cookie", sb.toString());
412            }
413    
414            private static final String _GET_ATTRIBUTES = "/identity/attributes";
415    
416            private static final String _GET_COOKIE_NAME =
417                    "/identity/getCookieNameForToken";
418    
419            private static final String _GET_COOKIE_NAMES =
420                    "/identity/getCookieNamesToForward";
421    
422            private static final String _VALIDATE_TOKEN = "/identity/isTokenValid";
423    
424            private static Log _log = LogFactoryUtil.getLog(OpenSSOUtil.class);
425    
426            private static OpenSSOUtil _instance = new OpenSSOUtil();
427    
428            private Map<String, String[]> _cookieNamesMap =
429                    new ConcurrentHashMap<String, String[]>();
430    
431    }