/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.security.sso.opensso.internal;
import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.security.sso.OpenSSO;
import com.liferay.portal.kernel.util.CookieKeys;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import org.osgi.service.component.annotations.Component;
/**
* @author Michael C. Han
*/
@Component(immediate = true, service = OpenSSO.class)
public class OpenSSOImpl implements OpenSSO {
@Override
public Map<String, String> getAttributes(
HttpServletRequest request, String serviceUrl) {
Map<String, String> nameValues = new HashMap<>();
String url = serviceUrl.concat(_GET_ATTRIBUTES);
try {
URL urlObj = new URL(url);
HttpURLConnection httpURLConnection =
(HttpURLConnection)urlObj.openConnection();
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty(
"Content-type", "application/x-www-form-urlencoded");
String[] cookieNames = getCookieNames(serviceUrl);
setCookieProperty(request, httpURLConnection, cookieNames);
OutputStreamWriter osw = new OutputStreamWriter(
httpURLConnection.getOutputStream());
osw.write("dummy");
osw.flush();
int responseCode = httpURLConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream =
(InputStream)httpURLConnection.getContent();
UnsyncBufferedReader unsyncBufferedReader =
new UnsyncBufferedReader(
new InputStreamReader(inputStream));
String line = null;
while ((line = unsyncBufferedReader.readLine()) != null) {
if (line.startsWith("userdetails.attribute.name=")) {
String name = line.replaceFirst(
"userdetails.attribute.name=", "");
line = unsyncBufferedReader.readLine();
if (line.startsWith("userdetails.attribute.value=")) {
String value = line.replaceFirst(
"userdetails.attribute.value=", "");
nameValues.put(name, value);
}
}
}
}
else if (_log.isDebugEnabled()) {
_log.debug("Attributes response code " + responseCode);
}
}
catch (MalformedURLException murle) {
_log.error(murle.getMessage());
if (_log.isDebugEnabled()) {
_log.debug(murle, murle);
}
}
catch (IOException ioe) {
_log.error(ioe.getMessage());
if (_log.isDebugEnabled()) {
_log.debug(ioe, ioe);
}
}
return nameValues;
}
public String[] getCookieNames(String serviceUrl) {
String[] cookieNames = _cookieNamesMap.get(serviceUrl);
if (cookieNames != null) {
return cookieNames;
}
List<String> cookieNamesList = new ArrayList<>();
try {
String cookieName = null;
String url = serviceUrl.concat(_GET_COOKIE_NAME);
URL urlObj = new URL(url);
HttpURLConnection httpURLConnection =
(HttpURLConnection)urlObj.openConnection();
InputStream inputStream =
(InputStream)httpURLConnection.getContent();
UnsyncBufferedReader unsyncBufferedReader =
new UnsyncBufferedReader(new InputStreamReader(inputStream));
int responseCode = httpURLConnection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
if (_log.isDebugEnabled()) {
_log.debug(url + " has response code " + responseCode);
}
}
else {
String line = null;
while ((line = unsyncBufferedReader.readLine()) != null) {
if (line.startsWith("string=")) {
line = line.replaceFirst("string=", "");
cookieName = line;
}
}
}
url = serviceUrl.concat(_GET_COOKIE_NAMES);
urlObj = new URL(url);
httpURLConnection = (HttpURLConnection)urlObj.openConnection();
inputStream = (InputStream)httpURLConnection.getContent();
unsyncBufferedReader = new UnsyncBufferedReader(
new InputStreamReader(inputStream));
if (httpURLConnection.getResponseCode() !=
HttpURLConnection.HTTP_OK) {
if (_log.isDebugEnabled()) {
_log.debug(url + " has response code " + responseCode);
}
}
else {
String line = null;
while ((line = unsyncBufferedReader.readLine()) != null) {
if (line.startsWith("string=")) {
line = line.replaceFirst("string=", "");
if (cookieName.equals(line)) {
cookieNamesList.add(0, cookieName);
}
else {
cookieNamesList.add(line);
}
}
}
}
}
catch (IOException ioe) {
if (_log.isWarnEnabled()) {
_log.warn(ioe, ioe);
}
}
cookieNames = cookieNamesList.toArray(
new String[cookieNamesList.size()]);
if (cookieNames.length > 0) {
_cookieNamesMap.put(serviceUrl, cookieNames);
}
return cookieNames;
}
@Override
public String getSubjectId(HttpServletRequest request, String serviceUrl) {
String cookieName = getCookieNames(serviceUrl)[0];
return CookieKeys.getCookie(request, cookieName);
}
@Override
public boolean isAuthenticated(
HttpServletRequest request, String serviceUrl)
throws IOException {
boolean authenticated = false;
boolean hasCookieNames = false;
String[] cookieNames = getCookieNames(serviceUrl);
for (String cookieName : cookieNames) {
if (CookieKeys.getCookie(request, cookieName) != null) {
hasCookieNames = true;
break;
}
}
if (!hasCookieNames) {
if (_log.isInfoEnabled()) {
_log.info(
"User is not logged in because he has no OpenSSO cookies");
}
return false;
}
String url = serviceUrl.concat(_VALIDATE_TOKEN);
URL urlObj = new URL(url);
HttpURLConnection httpURLConnection =
(HttpURLConnection)urlObj.openConnection();
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty(
"Content-type", "application/x-www-form-urlencoded");
setCookieProperty(request, httpURLConnection, cookieNames);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
httpURLConnection.getOutputStream());
outputStreamWriter.write("dummy");
outputStreamWriter.flush();
int responseCode = httpURLConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
String data = StringUtil.read(httpURLConnection.getInputStream());
if (StringUtil.toLowerCase(data).contains("boolean=true")) {
authenticated = true;
}
}
else if (_log.isDebugEnabled()) {
_log.debug("Authentication response code " + responseCode);
}
return authenticated;
}
@Override
public boolean isValidServiceUrl(String serviceUrl) {
if (Validator.isNull(serviceUrl)) {
return false;
}
String[] cookieNames = getCookieNames(serviceUrl);
if (cookieNames.length == 0) {
return false;
}
return true;
}
@Override
public boolean isValidUrl(String url) {
if (Validator.isNull(url)) {
return false;
}
try {
URL urlObj = new URL(url);
HttpURLConnection httpURLConnection =
(HttpURLConnection)urlObj.openConnection();
int responseCode = httpURLConnection.getResponseCode();
if (!((responseCode == HttpURLConnection.HTTP_OK) ||
((responseCode >= HttpURLConnection.HTTP_MULT_CHOICE) &&
(responseCode <= HttpURLConnection.HTTP_NOT_MODIFIED)))) {
if (_log.isDebugEnabled()) {
_log.debug(
"URL " + url + " is invalid with response code " +
responseCode);
}
return false;
}
if (_log.isDebugEnabled()) {
_log.debug(
"URL " + url + " is valid with response code " +
responseCode);
}
}
catch (IOException ioe) {
if (_log.isWarnEnabled()) {
_log.warn(ioe, ioe);
}
return false;
}
return true;
}
@Override
public boolean isValidUrls(String[] urls) {
for (String url : urls) {
if (!isValidUrl(url)) {
return false;
}
}
return true;
}
public void setCookieProperty(
HttpServletRequest request, HttpURLConnection urlc,
String[] cookieNames) {
if (cookieNames.length == 0) {
return;
}
StringBundler sb = new StringBundler(cookieNames.length * 6);
for (String cookieName : cookieNames) {
String cookieValue = CookieKeys.getCookie(request, cookieName);
sb.append(cookieName);
sb.append(StringPool.EQUAL);
sb.append(StringPool.QUOTE);
sb.append(cookieValue);
sb.append(StringPool.QUOTE);
sb.append(StringPool.SEMICOLON);
}
urlc.setRequestProperty("Cookie", sb.toString());
}
private static final String _GET_ATTRIBUTES = "/identity/attributes";
private static final String _GET_COOKIE_NAME =
"/identity/getCookieNameForToken";
private static final String _GET_COOKIE_NAMES =
"/identity/getCookieNamesToForward";
private static final String _VALIDATE_TOKEN = "/identity/isTokenValid";
private static final Log _log = LogFactoryUtil.getLog(OpenSSOImpl.class);
private final Map<String, String[]> _cookieNamesMap =
new ConcurrentHashMap<>();
}