/**
* 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.auth.tunnel;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.security.auth.AuthException;
import com.liferay.portal.kernel.security.auth.RemoteAuthException;
import com.liferay.portal.kernel.security.auth.http.HttpAuthManagerUtil;
import com.liferay.portal.kernel.security.auth.http.HttpAuthorizationHeader;
import com.liferay.portal.kernel.security.auth.tunnel.TunnelAuthenticationManager;
import com.liferay.portal.kernel.service.UserLocalServiceUtil;
import com.liferay.portal.kernel.servlet.HttpHeaders;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.util.PortalInstances;
import com.liferay.portal.util.PropsValues;
import com.liferay.util.Encryptor;
import com.liferay.util.EncryptorException;
import java.net.HttpURLConnection;
import java.security.Key;
import java.util.Objects;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
/**
* @author Tomas Polesovsky
*/
public class TunnelAuthenticationManagerImpl
implements TunnelAuthenticationManager {
@Override
public long getUserId(HttpServletRequest httpServletRequest)
throws AuthException {
HttpAuthorizationHeader httpAuthorizationHeader =
HttpAuthManagerUtil.parse(httpServletRequest);
if (httpAuthorizationHeader == null) {
return 0;
}
String scheme = httpAuthorizationHeader.getScheme();
if (!StringUtil.equalsIgnoreCase(
scheme, HttpAuthorizationHeader.SCHEME_BASIC)) {
AuthException authException = new RemoteAuthException(
"Invalid scheme " + scheme);
authException.setType(AuthException.INTERNAL_SERVER_ERROR);
throw authException;
}
String expectedPassword = null;
String login = httpAuthorizationHeader.getAuthParameter(
HttpAuthorizationHeader.AUTH_PARAMETER_NAME_USERNAME);
try {
expectedPassword = Encryptor.encrypt(getSharedSecretKey(), login);
}
catch (EncryptorException ee) {
AuthException authException = new RemoteAuthException(ee);
authException.setType(AuthException.INTERNAL_SERVER_ERROR);
throw authException;
}
catch (AuthException ae) {
AuthException authException = new RemoteAuthException(ae);
authException.setType(ae.getType());
throw authException;
}
String password = httpAuthorizationHeader.getAuthParameter(
HttpAuthorizationHeader.AUTH_PARAMETER_NAME_PASSWORD);
if (!Objects.equals(expectedPassword, password)) {
AuthException authException = new RemoteAuthException();
authException.setType(RemoteAuthException.WRONG_SHARED_SECRET);
throw authException;
}
User user = UserLocalServiceUtil.fetchUser(GetterUtil.getLong(login));
if (user == null) {
long companyId = PortalInstances.getCompanyId(httpServletRequest);
user = UserLocalServiceUtil.fetchUserByEmailAddress(
companyId, login);
if (user == null) {
user = UserLocalServiceUtil.fetchUserByScreenName(
companyId, login);
}
}
if (user == null) {
AuthException authException = new RemoteAuthException(
"Unable to find user " + login);
authException.setType(AuthException.INTERNAL_SERVER_ERROR);
throw authException;
}
return user.getUserId();
}
@Override
public void setCredentials(
String login, HttpURLConnection httpURLConnection)
throws Exception {
if (Validator.isBlank(login)) {
throw new IllegalArgumentException("Login is null");
}
HttpAuthorizationHeader httpAuthorizationHeader =
new HttpAuthorizationHeader(HttpAuthorizationHeader.SCHEME_BASIC);
String password = Encryptor.encrypt(getSharedSecretKey(), login);
httpAuthorizationHeader.setAuthParameter(
HttpAuthorizationHeader.AUTH_PARAMETER_NAME_PASSWORD, password);
httpAuthorizationHeader.setAuthParameter(
HttpAuthorizationHeader.AUTH_PARAMETER_NAME_USERNAME, login);
httpURLConnection.setRequestProperty(
HttpHeaders.AUTHORIZATION, httpAuthorizationHeader.toString());
}
protected Key getSharedSecretKey() throws AuthException {
String sharedSecret = PropsValues.TUNNELING_SERVLET_SHARED_SECRET;
boolean sharedSecretHex =
PropsValues.TUNNELING_SERVLET_SHARED_SECRET_HEX;
if (Validator.isNull(sharedSecret)) {
String message =
"Please configure " + PropsKeys.TUNNELING_SERVLET_SHARED_SECRET;
if (_log.isWarnEnabled()) {
_log.warn(message);
}
AuthException authException = new AuthException(message);
authException.setType(AuthException.NO_SHARED_SECRET);
throw authException;
}
byte[] key = null;
if (sharedSecretHex) {
try {
key = Hex.decodeHex(sharedSecret.toCharArray());
}
catch (DecoderException de) {
if (_log.isWarnEnabled()) {
_log.warn(de, de);
}
AuthException authException = new AuthException();
authException.setType(AuthException.INVALID_SHARED_SECRET);
throw authException;
}
}
else {
key = sharedSecret.getBytes();
}
if (key.length < 8) {
String message =
PropsKeys.TUNNELING_SERVLET_SHARED_SECRET + " is too short";
if (_log.isWarnEnabled()) {
_log.warn(message);
}
AuthException authException = new AuthException(message);
authException.setType(AuthException.INVALID_SHARED_SECRET);
throw authException;
}
if (StringUtil.equalsIgnoreCase(
PropsValues.TUNNELING_SERVLET_ENCRYPTION_ALGORITHM, "AES") &&
(key.length != 16) && (key.length != 32)) {
String message =
PropsKeys.TUNNELING_SERVLET_SHARED_SECRET +
" must have 16 or 32 bytes when used with AES";
if (_log.isWarnEnabled()) {
_log.warn(message);
}
AuthException authException = new AuthException(message);
authException.setType(AuthException.INVALID_SHARED_SECRET);
throw authException;
}
return new SecretKeySpec(
key, PropsValues.TUNNELING_SERVLET_ENCRYPTION_ALGORITHM);
}
private static final Log _log = LogFactoryUtil.getLog(
TunnelAuthenticationManagerImpl.class);
}