001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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.StringBundler;
021    import com.liferay.portal.kernel.util.StringPool;
022    import com.liferay.portal.kernel.util.StringUtil;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.util.CookieUtil;
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 mfue) {
150                            _log.error(mfue.getMessage());
151    
152                            if (_log.isDebugEnabled()) {
153                                    _log.debug(mfue, mfue);
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(
191                                            new InputStreamReader(inputStream));
192    
193                            int responseCode = httpURLConnection.getResponseCode();
194    
195                            if (responseCode != HttpURLConnection.HTTP_OK) {
196                                    if (_log.isDebugEnabled()) {
197                                            _log.debug(url + " has response code " + responseCode);
198                                    }
199                            }
200                            else {
201                                    String line = null;
202    
203                                    while ((line = unsyncBufferedReader.readLine()) != null) {
204                                            if (line.startsWith("string=")) {
205                                                    line = line.replaceFirst("string=", "");
206    
207                                                    cookieName = line;
208                                            }
209                                    }
210                            }
211    
212                            url = serviceUrl.concat(_GET_COOKIE_NAMES);
213    
214                            urlObj = new URL(url);
215    
216                            httpURLConnection = (HttpURLConnection)urlObj.openConnection();
217    
218                            inputStream = (InputStream)httpURLConnection.getContent();
219    
220                            unsyncBufferedReader = new UnsyncBufferedReader(
221                                    new InputStreamReader(inputStream));
222    
223                            if (httpURLConnection.getResponseCode() !=
224                                            HttpURLConnection.HTTP_OK) {
225    
226                                    if (_log.isDebugEnabled()) {
227                                            _log.debug(url + " has response code " + responseCode);
228                                    }
229                            }
230                            else {
231                                    String line = null;
232    
233                                    while ((line = unsyncBufferedReader.readLine()) != null) {
234                                            if (line.startsWith("string=")) {
235                                                    line = line.replaceFirst("string=", "");
236    
237                                                    if (cookieName.equals(line)) {
238                                                            cookieNamesList.add(0, cookieName);
239                                                    }
240                                                    else {
241                                                            cookieNamesList.add(line);
242                                                    }
243                                            }
244                                    }
245                            }
246                    }
247                    catch (IOException ioe) {
248                            if (_log.isWarnEnabled()) {
249                                    _log.warn(ioe, ioe);
250                            }
251                    }
252    
253                    cookieNames = cookieNamesList.toArray(
254                            new String[cookieNamesList.size()]);
255    
256                    if (cookieNames.length > 0) {
257                            _cookieNamesMap.put(serviceUrl, cookieNames);
258                    }
259    
260                    return cookieNames;
261            }
262    
263            private String _getSubjectId(
264                    HttpServletRequest request, String serviceUrl) {
265    
266                    String cookieName = _getCookieNames(serviceUrl)[0];
267    
268                    return CookieUtil.get(request, cookieName);
269            }
270    
271            private boolean _isAuthenticated(
272                            HttpServletRequest request, String serviceUrl)
273                    throws IOException {
274    
275                    boolean authenticated = false;
276    
277                    boolean hasCookieNames = false;
278    
279                    String[] cookieNames = _getCookieNames(serviceUrl);
280    
281                    for (String cookieName : cookieNames) {
282                            if (CookieUtil.get(request, cookieName) != null) {
283                                    hasCookieNames = true;
284    
285                                    break;
286                            }
287                    }
288    
289                    if (!hasCookieNames) {
290                            if (_log.isWarnEnabled()) {
291                                    _log.warn(
292                                            "User is not logged in because he has no OpenSSO cookies");
293                            }
294    
295                            return false;
296                    }
297    
298                    String url = serviceUrl.concat(_VALIDATE_TOKEN);
299    
300                    URL urlObj = new URL(url);
301    
302                    HttpURLConnection httpURLConnection =
303                            (HttpURLConnection)urlObj.openConnection();
304    
305                    httpURLConnection.setDoOutput(true);
306                    httpURLConnection.setRequestMethod("POST");
307                    httpURLConnection.setRequestProperty(
308                            "Content-type", "application/x-www-form-urlencoded");
309    
310                    _setCookieProperty(request, httpURLConnection, cookieNames);
311    
312                    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
313                            httpURLConnection.getOutputStream());
314    
315                    outputStreamWriter.write("dummy");
316    
317                    outputStreamWriter.flush();
318    
319                    int responseCode = httpURLConnection.getResponseCode();
320    
321                    if (responseCode == HttpURLConnection.HTTP_OK) {
322                            String data = StringUtil.read(httpURLConnection.getInputStream());
323    
324                            if (data.toLowerCase().indexOf("boolean=true") != -1) {
325                                    authenticated = true;
326                            }
327                    }
328                    else if (_log.isDebugEnabled()) {
329                            _log.debug("Authentication response code " + responseCode);
330                    }
331    
332                    return authenticated;
333            }
334    
335            private boolean _isValidServiceUrl(String serviceUrl) {
336                    if (Validator.isNull(serviceUrl)) {
337                            return false;
338                    }
339    
340                    String[] cookieNames = _instance._getCookieNames(serviceUrl);
341    
342                    if (cookieNames.length == 0) {
343                            return false;
344                    }
345    
346                    return true;
347            }
348    
349            private boolean _isValidUrl(String url) {
350                    if (Validator.isNull(url)) {
351                            return false;
352                    }
353    
354                    try {
355                            URL urlObj = new URL(url);
356    
357                            HttpURLConnection httpURLConnection =
358                                    (HttpURLConnection)urlObj.openConnection();
359    
360                            int responseCode = httpURLConnection.getResponseCode();
361    
362                            if (responseCode != HttpURLConnection.HTTP_OK) {
363                                    if (_log.isDebugEnabled()) {
364                                            _log.debug("Attributes response code " + responseCode);
365                                    }
366    
367                                    return false;
368                            }
369                    }
370                    catch (IOException ioe) {
371                            if (_log.isWarnEnabled()) {
372                                    _log.warn(ioe, ioe);
373                            }
374    
375                            return false;
376                    }
377    
378                    return true;
379            }
380    
381            private boolean _isValidUrls(String[] urls) {
382                    for (String url : urls) {
383                            if (!_isValidUrl(url)) {
384                                    return false;
385                            }
386                    }
387    
388                    return true;
389            }
390    
391            private void _setCookieProperty(
392                    HttpServletRequest request, HttpURLConnection urlc,
393                    String[] cookieNames) {
394    
395                    if (cookieNames.length == 0) {
396                            return;
397                    }
398    
399                    StringBundler sb = new StringBundler(cookieNames.length * 4);
400    
401                    for (String cookieName : cookieNames) {
402                            String cookieValue = CookieUtil.get(request, cookieName);
403    
404                            sb.append(cookieName);
405                            sb.append(StringPool.EQUAL);
406                            sb.append(StringPool.QUOTE);
407                            sb.append(cookieValue);
408                            sb.append(StringPool.QUOTE);
409                            sb.append(StringPool.SEMICOLON);
410                    }
411    
412                    urlc.setRequestProperty("Cookie", sb.toString());
413            }
414    
415            private static final String _GET_ATTRIBUTES = "/identity/attributes";
416    
417            private static final String _GET_COOKIE_NAME =
418                    "/identity/getCookieNameForToken";
419    
420            private static final String _GET_COOKIE_NAMES =
421                    "/identity/getCookieNamesToForward";
422    
423            private static final String _VALIDATE_TOKEN = "/identity/isTokenValid";
424    
425            private static Log _log = LogFactoryUtil.getLog(OpenSSOUtil.class);
426    
427            private static OpenSSOUtil _instance = new OpenSSOUtil();
428    
429            private Map<String, String[]> _cookieNamesMap =
430                    new ConcurrentHashMap<String, String[]>();
431    
432    }