001
014
015 package com.liferay.portal.security.auth;
016
017 import com.liferay.portal.kernel.exception.PortalException;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.security.auth.AccessControlContext;
021 import com.liferay.portal.kernel.security.auth.verifier.AuthVerifier;
022 import com.liferay.portal.kernel.security.auth.verifier.AuthVerifierConfiguration;
023 import com.liferay.portal.kernel.security.auth.verifier.AuthVerifierResult;
024 import com.liferay.portal.kernel.util.PropsKeys;
025 import com.liferay.portal.kernel.util.StringPool;
026 import com.liferay.portal.kernel.util.StringUtil;
027 import com.liferay.portal.service.UserLocalServiceUtil;
028 import com.liferay.portal.util.PortalUtil;
029 import com.liferay.registry.Filter;
030 import com.liferay.registry.Registry;
031 import com.liferay.registry.RegistryUtil;
032 import com.liferay.registry.ServiceReference;
033 import com.liferay.registry.ServiceTracker;
034 import com.liferay.registry.ServiceTrackerCustomizer;
035
036 import java.util.ArrayList;
037 import java.util.HashMap;
038 import java.util.Iterator;
039 import java.util.List;
040 import java.util.Map;
041 import java.util.Properties;
042 import java.util.Set;
043 import java.util.concurrent.CopyOnWriteArrayList;
044
045 import javax.servlet.http.HttpServletRequest;
046
047 import jodd.util.Wildcard;
048
049
053 public class AuthVerifierPipeline {
054
055 public static final String AUTH_TYPE = "auth.type";
056
057 public static String getAuthVerifierPropertyName(String className) {
058 String simpleClassName = StringUtil.extractLast(
059 className, StringPool.PERIOD);
060
061 return PropsKeys.AUTH_VERIFIER.concat(simpleClassName).concat(
062 StringPool.PERIOD);
063 }
064
065 public static AuthVerifierResult verifyRequest(
066 AccessControlContext accessControlContext)
067 throws PortalException {
068
069 return _instance._verifyRequest(accessControlContext);
070 }
071
072 private AuthVerifierPipeline() {
073 Registry registry = RegistryUtil.getRegistry();
074
075 Filter filter = registry.getFilter(
076 "(objectClass=" + AuthVerifier.class.getName() + ")");
077
078 _serviceTracker = registry.trackServices(
079 filter, new AuthVerifierTrackerCustomizer());
080
081 _serviceTracker.open();
082 }
083
084 private AuthVerifierResult _createGuestVerificationResult(
085 AccessControlContext accessControlContext)
086 throws PortalException {
087
088 AuthVerifierResult authVerifierResult = new AuthVerifierResult();
089
090 authVerifierResult.setState(AuthVerifierResult.State.SUCCESS);
091
092 HttpServletRequest request = accessControlContext.getRequest();
093
094 long companyId = PortalUtil.getCompanyId(request);
095
096 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
097
098 authVerifierResult.setUserId(defaultUserId);
099
100 return authVerifierResult;
101 }
102
103 private List<AuthVerifierConfiguration> _getAuthVerifierConfigurations(
104 AccessControlContext accessControlContext) {
105
106 HttpServletRequest request = accessControlContext.getRequest();
107
108 List<AuthVerifierConfiguration> authVerifierConfigurations =
109 new ArrayList<>();
110
111 String requestURI = request.getRequestURI();
112
113 String contextPath = request.getContextPath();
114
115 requestURI = requestURI.substring(contextPath.length());
116
117 for (AuthVerifierConfiguration authVerifierConfiguration :
118 _authVerifierConfigurations) {
119
120 authVerifierConfiguration = _mergeAuthVerifierConfiguration(
121 authVerifierConfiguration, accessControlContext);
122
123 if (_isMatchingRequestURI(authVerifierConfiguration, requestURI)) {
124 authVerifierConfigurations.add(authVerifierConfiguration);
125 }
126 }
127
128 return authVerifierConfigurations;
129 }
130
131 private boolean _isMatchingRequestURI(
132 AuthVerifierConfiguration authVerifierConfiguration,
133 String requestURI) {
134
135 Properties properties = authVerifierConfiguration.getProperties();
136
137 String[] urlsExcludes = StringUtil.split(
138 properties.getProperty("urls.excludes"));
139
140 if ((urlsExcludes.length > 0) &&
141 (Wildcard.matchOne(requestURI, urlsExcludes) > -1)) {
142
143 return false;
144 }
145
146 String[] urlsIncludes = StringUtil.split(
147 properties.getProperty("urls.includes"));
148
149 if (urlsIncludes.length == 0) {
150 return false;
151 }
152
153 return Wildcard.matchOne(requestURI, urlsIncludes) > -1;
154 }
155
156 private AuthVerifierConfiguration _mergeAuthVerifierConfiguration(
157 AuthVerifierConfiguration authVerifierConfiguration,
158 AccessControlContext accessControlContext) {
159
160 Map<String, Object> settings = accessControlContext.getSettings();
161
162 String authVerifierSettingsKey = getAuthVerifierPropertyName(
163 authVerifierConfiguration.getAuthVerifierClassName());
164
165 boolean merge = false;
166
167 Set<String> settingsKeys = settings.keySet();
168
169 Iterator<String> iterator = settingsKeys.iterator();
170
171 while (iterator.hasNext() && !merge) {
172 String settingsKey = iterator.next();
173
174 if (settingsKey.startsWith(authVerifierSettingsKey)) {
175 if (settings.get(settingsKey) instanceof String) {
176 merge = true;
177 }
178 }
179 }
180
181 if (!merge) {
182 return authVerifierConfiguration;
183 }
184
185 AuthVerifierConfiguration mergedAuthVerifierConfiguration =
186 new AuthVerifierConfiguration();
187
188 mergedAuthVerifierConfiguration.setAuthVerifier(
189 authVerifierConfiguration.getAuthVerifier());
190
191 Properties mergedProperties = new Properties(
192 authVerifierConfiguration.getProperties());
193
194 for (String settingsKey : settings.keySet()) {
195 if (settingsKey.startsWith(authVerifierSettingsKey)) {
196 Object settingsValue = settings.get(settingsKey);
197
198 if (settingsValue instanceof String) {
199 String propertiesKey = settingsKey.substring(
200 authVerifierSettingsKey.length());
201
202 mergedProperties.setProperty(
203 propertiesKey, (String)settingsValue);
204 }
205 }
206 }
207
208 mergedAuthVerifierConfiguration.setProperties(mergedProperties);
209
210 return mergedAuthVerifierConfiguration;
211 }
212
213 private Map<String, Object> _mergeSettings(
214 Properties properties, Map<String, Object> settings) {
215
216 Map<String, Object> mergedSettings = new HashMap<>(settings);
217
218 if (properties != null) {
219 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
220 mergedSettings.put((String)entry.getKey(), entry.getValue());
221 }
222 }
223
224 return mergedSettings;
225 }
226
227 private AuthVerifierResult _verifyRequest(
228 AccessControlContext accessControlContext)
229 throws PortalException {
230
231 if (accessControlContext == null) {
232 throw new IllegalArgumentException(
233 "Access control context is null");
234 }
235
236 List<AuthVerifierConfiguration> authVerifierConfigurations =
237 _getAuthVerifierConfigurations(accessControlContext);
238
239 for (AuthVerifierConfiguration authVerifierConfiguration :
240 authVerifierConfigurations) {
241
242 AuthVerifierResult authVerifierResult = null;
243
244 AuthVerifier authVerifier =
245 authVerifierConfiguration.getAuthVerifier();
246
247 Properties properties = authVerifierConfiguration.getProperties();
248
249 try {
250 authVerifierResult = authVerifier.verify(
251 accessControlContext, properties);
252 }
253 catch (Exception e) {
254 if (_log.isDebugEnabled()) {
255 Class<?> authVerifierClass = authVerifier.getClass();
256
257 _log.debug("Skipping " + authVerifierClass.getName(), e);
258 }
259
260 continue;
261 }
262
263 if (authVerifierResult == null) {
264 Class<?> authVerifierClass = authVerifier.getClass();
265
266 _log.error(
267 "Auth verifier " + authVerifierClass.getName() +
268 " did not return an auth verifier result");
269
270 continue;
271 }
272
273 if (authVerifierResult.getState() !=
274 AuthVerifierResult.State.NOT_APPLICABLE) {
275
276 Map<String, Object> settings = _mergeSettings(
277 properties, authVerifierResult.getSettings());
278
279 settings.put(AUTH_TYPE, authVerifier.getAuthType());
280
281 authVerifierResult.setSettings(settings);
282
283 return authVerifierResult;
284 }
285 }
286
287 return _createGuestVerificationResult(accessControlContext);
288 }
289
290 private static final Log _log = LogFactoryUtil.getLog(
291 AuthVerifierPipeline.class);
292
293 private static final AuthVerifierPipeline _instance =
294 new AuthVerifierPipeline();
295
296 private final List<AuthVerifierConfiguration> _authVerifierConfigurations =
297 new CopyOnWriteArrayList<>();
298 private final ServiceTracker<AuthVerifier, AuthVerifierConfiguration>
299 _serviceTracker;
300
301 private class AuthVerifierTrackerCustomizer
302 implements
303 ServiceTrackerCustomizer<AuthVerifier, AuthVerifierConfiguration> {
304
305 @Override
306 public AuthVerifierConfiguration addingService(
307 ServiceReference<AuthVerifier> serviceReference) {
308
309 Registry registry = RegistryUtil.getRegistry();
310
311 AuthVerifier authVerifier = registry.getService(serviceReference);
312
313 if (authVerifier == null) {
314 return null;
315 }
316
317 Class<?> authVerifierClass = authVerifier.getClass();
318
319 AuthVerifierConfiguration authVerifierConfiguration =
320 new AuthVerifierConfiguration();
321
322 authVerifierConfiguration.setAuthVerifier(authVerifier);
323 authVerifierConfiguration.setAuthVerifierClassName(
324 authVerifierClass.getName());
325 authVerifierConfiguration.setProperties(
326 _loadProperties(serviceReference, authVerifierClass.getName()));
327
328 if (!_validate(authVerifierConfiguration)) {
329 return null;
330 }
331
332 _authVerifierConfigurations.add(0, authVerifierConfiguration);
333
334 return authVerifierConfiguration;
335 }
336
337 @Override
338 public void modifiedService(
339 ServiceReference<AuthVerifier> serviceReference,
340 AuthVerifierConfiguration authVerifierConfiguration) {
341
342 AuthVerifierConfiguration newAuthVerifierConfiguration =
343 new AuthVerifierConfiguration();
344
345 newAuthVerifierConfiguration.setAuthVerifier(
346 authVerifierConfiguration.getAuthVerifier());
347 newAuthVerifierConfiguration.setAuthVerifierClassName(
348 authVerifierConfiguration.getAuthVerifierClassName());
349 newAuthVerifierConfiguration.setProperties(
350 _loadProperties(
351 serviceReference,
352 authVerifierConfiguration.getAuthVerifierClassName()));
353
354 if (_authVerifierConfigurations.remove(authVerifierConfiguration)) {
355 if (!_validate(authVerifierConfiguration)) {
356 return;
357 }
358
359 _authVerifierConfigurations.add(
360 0, newAuthVerifierConfiguration);
361 }
362 }
363
364 @Override
365 public void removedService(
366 ServiceReference<AuthVerifier> serviceReference,
367 AuthVerifierConfiguration authVerifierConfiguration) {
368
369 Registry registry = RegistryUtil.getRegistry();
370
371 registry.ungetService(serviceReference);
372
373 _authVerifierConfigurations.remove(authVerifierConfiguration);
374 }
375
376 private Properties _loadProperties(
377 ServiceReference<AuthVerifier> serviceReference,
378 String authVerifierClassName) {
379
380 Properties properties = new Properties();
381
382 String authVerifierPropertyName = getAuthVerifierPropertyName(
383 authVerifierClassName);
384
385 Map<String, Object> serviceReferenceProperties =
386 serviceReference.getProperties();
387
388 for (String key : serviceReferenceProperties.keySet()) {
389 String propertiesKey = key;
390
391 if (key.startsWith(authVerifierPropertyName)) {
392 propertiesKey = key.substring(
393 authVerifierPropertyName.length());
394 }
395
396 Object value = serviceReferenceProperties.get(key);
397
398 properties.setProperty(propertiesKey, String.valueOf(value));
399 }
400
401 return properties;
402 }
403
404 private boolean _validate(
405 AuthVerifierConfiguration authVerifierConfiguration) {
406
407 Properties properties = authVerifierConfiguration.getProperties();
408
409 String[] urlsIncludes = StringUtil.split(
410 properties.getProperty("urls.includes"));
411
412 if (urlsIncludes.length == 0) {
413 if (_log.isWarnEnabled()) {
414 String authVerifierClassName =
415 authVerifierConfiguration.getAuthVerifierClassName();
416
417 _log.warn(
418 "Auth verifier " + authVerifierClassName +
419 " does not have URLs configured");
420 }
421
422 return false;
423 }
424
425 return true;
426 }
427
428 }
429
430 }