001
014
015 package com.liferay.portal.security.auth.tunnel;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.model.User;
020 import com.liferay.portal.kernel.security.auth.AuthException;
021 import com.liferay.portal.kernel.security.auth.RemoteAuthException;
022 import com.liferay.portal.kernel.security.auth.http.HttpAuthManagerUtil;
023 import com.liferay.portal.kernel.security.auth.http.HttpAuthorizationHeader;
024 import com.liferay.portal.kernel.security.auth.tunnel.TunnelAuthenticationManager;
025 import com.liferay.portal.kernel.service.UserLocalServiceUtil;
026 import com.liferay.portal.kernel.servlet.HttpHeaders;
027 import com.liferay.portal.kernel.util.GetterUtil;
028 import com.liferay.portal.kernel.util.PropsKeys;
029 import com.liferay.portal.kernel.util.StringUtil;
030 import com.liferay.portal.kernel.util.Validator;
031 import com.liferay.portal.util.PortalInstances;
032 import com.liferay.portal.util.PropsValues;
033 import com.liferay.util.Encryptor;
034 import com.liferay.util.EncryptorException;
035
036 import java.net.HttpURLConnection;
037
038 import java.security.Key;
039
040 import java.util.Objects;
041
042 import javax.crypto.spec.SecretKeySpec;
043
044 import javax.servlet.http.HttpServletRequest;
045
046 import org.apache.commons.codec.DecoderException;
047 import org.apache.commons.codec.binary.Hex;
048
049
052 public class TunnelAuthenticationManagerImpl
053 implements TunnelAuthenticationManager {
054
055 @Override
056 public long getUserId(HttpServletRequest httpServletRequest)
057 throws AuthException {
058
059 HttpAuthorizationHeader httpAuthorizationHeader =
060 HttpAuthManagerUtil.parse(httpServletRequest);
061
062 if (httpAuthorizationHeader == null) {
063 return 0;
064 }
065
066 String scheme = httpAuthorizationHeader.getScheme();
067
068 if (!StringUtil.equalsIgnoreCase(
069 scheme, HttpAuthorizationHeader.SCHEME_BASIC)) {
070
071 AuthException authException = new RemoteAuthException(
072 "Invalid scheme " + scheme);
073
074 authException.setType(AuthException.INTERNAL_SERVER_ERROR);
075
076 throw authException;
077 }
078
079 String expectedPassword = null;
080
081 String login = httpAuthorizationHeader.getAuthParameter(
082 HttpAuthorizationHeader.AUTH_PARAMETER_NAME_USERNAME);
083
084 try {
085 expectedPassword = Encryptor.encrypt(getSharedSecretKey(), login);
086 }
087 catch (EncryptorException ee) {
088 AuthException authException = new RemoteAuthException(ee);
089
090 authException.setType(AuthException.INTERNAL_SERVER_ERROR);
091
092 throw authException;
093 }
094 catch (AuthException ae) {
095 AuthException authException = new RemoteAuthException(ae);
096
097 authException.setType(ae.getType());
098
099 throw authException;
100 }
101
102 String password = httpAuthorizationHeader.getAuthParameter(
103 HttpAuthorizationHeader.AUTH_PARAMETER_NAME_PASSWORD);
104
105 if (!Objects.equals(expectedPassword, password)) {
106 AuthException authException = new RemoteAuthException();
107
108 authException.setType(RemoteAuthException.WRONG_SHARED_SECRET);
109
110 throw authException;
111 }
112
113 User user = UserLocalServiceUtil.fetchUser(GetterUtil.getLong(login));
114
115 if (user == null) {
116 long companyId = PortalInstances.getCompanyId(httpServletRequest);
117
118 user = UserLocalServiceUtil.fetchUserByEmailAddress(
119 companyId, login);
120
121 if (user == null) {
122 user = UserLocalServiceUtil.fetchUserByScreenName(
123 companyId, login);
124 }
125 }
126
127 if (user == null) {
128 AuthException authException = new RemoteAuthException(
129 "Unable to find user " + login);
130
131 authException.setType(AuthException.INTERNAL_SERVER_ERROR);
132
133 throw authException;
134 }
135
136 return user.getUserId();
137 }
138
139 @Override
140 public void setCredentials(
141 String login, HttpURLConnection httpURLConnection)
142 throws Exception {
143
144 if (Validator.isBlank(login)) {
145 throw new IllegalArgumentException("Login is null");
146 }
147
148 HttpAuthorizationHeader httpAuthorizationHeader =
149 new HttpAuthorizationHeader(HttpAuthorizationHeader.SCHEME_BASIC);
150
151 String password = Encryptor.encrypt(getSharedSecretKey(), login);
152
153 httpAuthorizationHeader.setAuthParameter(
154 HttpAuthorizationHeader.AUTH_PARAMETER_NAME_PASSWORD, password);
155
156 httpAuthorizationHeader.setAuthParameter(
157 HttpAuthorizationHeader.AUTH_PARAMETER_NAME_USERNAME, login);
158 httpURLConnection.setRequestProperty(
159 HttpHeaders.AUTHORIZATION, httpAuthorizationHeader.toString());
160 }
161
162 protected Key getSharedSecretKey() throws AuthException {
163 String sharedSecret = PropsValues.TUNNELING_SERVLET_SHARED_SECRET;
164 boolean sharedSecretHex =
165 PropsValues.TUNNELING_SERVLET_SHARED_SECRET_HEX;
166
167 if (Validator.isNull(sharedSecret)) {
168 String message =
169 "Please configure " + PropsKeys.TUNNELING_SERVLET_SHARED_SECRET;
170
171 if (_log.isWarnEnabled()) {
172 _log.warn(message);
173 }
174
175 AuthException authException = new AuthException(message);
176
177 authException.setType(AuthException.NO_SHARED_SECRET);
178
179 throw authException;
180 }
181
182 byte[] key = null;
183
184 if (sharedSecretHex) {
185 try {
186 key = Hex.decodeHex(sharedSecret.toCharArray());
187 }
188 catch (DecoderException de) {
189 if (_log.isWarnEnabled()) {
190 _log.warn(de, de);
191 }
192
193 AuthException authException = new AuthException();
194
195 authException.setType(AuthException.INVALID_SHARED_SECRET);
196
197 throw authException;
198 }
199 }
200 else {
201 key = sharedSecret.getBytes();
202 }
203
204 if (key.length < 8) {
205 String message =
206 PropsKeys.TUNNELING_SERVLET_SHARED_SECRET + " is too short";
207
208 if (_log.isWarnEnabled()) {
209 _log.warn(message);
210 }
211
212 AuthException authException = new AuthException(message);
213
214 authException.setType(AuthException.INVALID_SHARED_SECRET);
215
216 throw authException;
217 }
218
219 if (StringUtil.equalsIgnoreCase(
220 PropsValues.TUNNELING_SERVLET_ENCRYPTION_ALGORITHM, "AES") &&
221 (key.length != 16) && (key.length != 32)) {
222
223 String message =
224 PropsKeys.TUNNELING_SERVLET_SHARED_SECRET +
225 " must have 16 or 32 bytes when used with AES";
226
227 if (_log.isWarnEnabled()) {
228 _log.warn(message);
229 }
230
231 AuthException authException = new AuthException(message);
232
233 authException.setType(AuthException.INVALID_SHARED_SECRET);
234
235 throw authException;
236 }
237
238 return new SecretKeySpec(
239 key, PropsValues.TUNNELING_SERVLET_ENCRYPTION_ALGORITHM);
240 }
241
242 private static final Log _log = LogFactoryUtil.getLog(
243 TunnelAuthenticationManagerImpl.class);
244
245 }