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