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.service.UserLocalServiceUtil;
025 import com.liferay.portal.kernel.util.PortalUtil;
026 import com.liferay.portal.kernel.util.PropsKeys;
027 import com.liferay.portal.kernel.util.StringPool;
028 import com.liferay.portal.kernel.util.StringUtil;
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 if (Wildcard.matchOne(requestURI, urlsIncludes) > -1) {
154 return true;
155 }
156
157 return false;
158 }
159
160 private AuthVerifierConfiguration _mergeAuthVerifierConfiguration(
161 AuthVerifierConfiguration authVerifierConfiguration,
162 AccessControlContext accessControlContext) {
163
164 Map<String, Object> settings = accessControlContext.getSettings();
165
166 String authVerifierSettingsKey = getAuthVerifierPropertyName(
167 authVerifierConfiguration.getAuthVerifierClassName());
168
169 boolean merge = false;
170
171 Set<String> settingsKeys = settings.keySet();
172
173 Iterator<String> iterator = settingsKeys.iterator();
174
175 while (iterator.hasNext() && !merge) {
176 String settingsKey = iterator.next();
177
178 if (settingsKey.startsWith(authVerifierSettingsKey)) {
179 if (settings.get(settingsKey) instanceof String) {
180 merge = true;
181 }
182 }
183 }
184
185 if (!merge) {
186 return authVerifierConfiguration;
187 }
188
189 AuthVerifierConfiguration mergedAuthVerifierConfiguration =
190 new AuthVerifierConfiguration();
191
192 mergedAuthVerifierConfiguration.setAuthVerifier(
193 authVerifierConfiguration.getAuthVerifier());
194
195 Properties mergedProperties = new Properties(
196 authVerifierConfiguration.getProperties());
197
198 for (Map.Entry<String, Object> entry : settings.entrySet()) {
199 String settingsKey = entry.getKey();
200
201 if (settingsKey.startsWith(authVerifierSettingsKey)) {
202 Object settingsValue = entry.getValue();
203
204 if (settingsValue instanceof String) {
205 String propertiesKey = settingsKey.substring(
206 authVerifierSettingsKey.length());
207
208 mergedProperties.setProperty(
209 propertiesKey, (String)settingsValue);
210 }
211 }
212 }
213
214 mergedAuthVerifierConfiguration.setProperties(mergedProperties);
215
216 return mergedAuthVerifierConfiguration;
217 }
218
219 private Map<String, Object> _mergeSettings(
220 Properties properties, Map<String, Object> settings) {
221
222 Map<String, Object> mergedSettings = new HashMap<>(settings);
223
224 if (properties != null) {
225 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
226 mergedSettings.put((String)entry.getKey(), entry.getValue());
227 }
228 }
229
230 return mergedSettings;
231 }
232
233 private AuthVerifierResult _verifyRequest(
234 AccessControlContext accessControlContext)
235 throws PortalException {
236
237 if (accessControlContext == null) {
238 throw new IllegalArgumentException(
239 "Access control context is null");
240 }
241
242 List<AuthVerifierConfiguration> authVerifierConfigurations =
243 _getAuthVerifierConfigurations(accessControlContext);
244
245 for (AuthVerifierConfiguration authVerifierConfiguration :
246 authVerifierConfigurations) {
247
248 AuthVerifierResult authVerifierResult = null;
249
250 AuthVerifier authVerifier =
251 authVerifierConfiguration.getAuthVerifier();
252
253 Properties properties = authVerifierConfiguration.getProperties();
254
255 try {
256 authVerifierResult = authVerifier.verify(
257 accessControlContext, properties);
258 }
259 catch (Exception e) {
260 if (_log.isDebugEnabled()) {
261 Class<?> authVerifierClass = authVerifier.getClass();
262
263 _log.debug("Skipping " + authVerifierClass.getName(), e);
264 }
265
266 continue;
267 }
268
269 if (authVerifierResult == null) {
270 Class<?> authVerifierClass = authVerifier.getClass();
271
272 _log.error(
273 "Auth verifier " + authVerifierClass.getName() +
274 " did not return an auth verifier result");
275
276 continue;
277 }
278
279 if (authVerifierResult.getState() !=
280 AuthVerifierResult.State.NOT_APPLICABLE) {
281
282 Map<String, Object> settings = _mergeSettings(
283 properties, authVerifierResult.getSettings());
284
285 settings.put(AUTH_TYPE, authVerifier.getAuthType());
286
287 authVerifierResult.setSettings(settings);
288
289 return authVerifierResult;
290 }
291 }
292
293 return _createGuestVerificationResult(accessControlContext);
294 }
295
296 private static final Log _log = LogFactoryUtil.getLog(
297 AuthVerifierPipeline.class);
298
299 private static final AuthVerifierPipeline _instance =
300 new AuthVerifierPipeline();
301
302 private final List<AuthVerifierConfiguration> _authVerifierConfigurations =
303 new CopyOnWriteArrayList<>();
304 private final ServiceTracker<AuthVerifier, AuthVerifierConfiguration>
305 _serviceTracker;
306
307 private class AuthVerifierTrackerCustomizer
308 implements
309 ServiceTrackerCustomizer<AuthVerifier, AuthVerifierConfiguration> {
310
311 @Override
312 public AuthVerifierConfiguration addingService(
313 ServiceReference<AuthVerifier> serviceReference) {
314
315 Registry registry = RegistryUtil.getRegistry();
316
317 AuthVerifier authVerifier = registry.getService(serviceReference);
318
319 if (authVerifier == null) {
320 return null;
321 }
322
323 Class<?> authVerifierClass = authVerifier.getClass();
324
325 AuthVerifierConfiguration authVerifierConfiguration =
326 new AuthVerifierConfiguration();
327
328 authVerifierConfiguration.setAuthVerifier(authVerifier);
329 authVerifierConfiguration.setAuthVerifierClassName(
330 authVerifierClass.getName());
331 authVerifierConfiguration.setProperties(
332 _loadProperties(serviceReference, authVerifierClass.getName()));
333
334 if (!_validate(authVerifierConfiguration)) {
335 return null;
336 }
337
338 _authVerifierConfigurations.add(0, authVerifierConfiguration);
339
340 return authVerifierConfiguration;
341 }
342
343 @Override
344 public void modifiedService(
345 ServiceReference<AuthVerifier> serviceReference,
346 AuthVerifierConfiguration authVerifierConfiguration) {
347
348 AuthVerifierConfiguration newAuthVerifierConfiguration =
349 new AuthVerifierConfiguration();
350
351 newAuthVerifierConfiguration.setAuthVerifier(
352 authVerifierConfiguration.getAuthVerifier());
353 newAuthVerifierConfiguration.setAuthVerifierClassName(
354 authVerifierConfiguration.getAuthVerifierClassName());
355 newAuthVerifierConfiguration.setProperties(
356 _loadProperties(
357 serviceReference,
358 authVerifierConfiguration.getAuthVerifierClassName()));
359
360 if (_authVerifierConfigurations.remove(authVerifierConfiguration)) {
361 if (!_validate(authVerifierConfiguration)) {
362 return;
363 }
364
365 _authVerifierConfigurations.add(
366 0, newAuthVerifierConfiguration);
367 }
368 }
369
370 @Override
371 public void removedService(
372 ServiceReference<AuthVerifier> serviceReference,
373 AuthVerifierConfiguration authVerifierConfiguration) {
374
375 Registry registry = RegistryUtil.getRegistry();
376
377 registry.ungetService(serviceReference);
378
379 _authVerifierConfigurations.remove(authVerifierConfiguration);
380 }
381
382 private Properties _loadProperties(
383 ServiceReference<AuthVerifier> serviceReference,
384 String authVerifierClassName) {
385
386 Properties properties = new Properties();
387
388 String authVerifierPropertyName = getAuthVerifierPropertyName(
389 authVerifierClassName);
390
391 Map<String, Object> serviceReferenceProperties =
392 serviceReference.getProperties();
393
394 for (Map.Entry<String, Object> entry :
395 serviceReferenceProperties.entrySet()) {
396
397 String key = entry.getKey();
398
399 if (key.startsWith(authVerifierPropertyName)) {
400 key = key.substring(authVerifierPropertyName.length());
401 }
402
403 Object value = entry.getValue();
404
405 properties.setProperty(key, String.valueOf(value));
406 }
407
408 return properties;
409 }
410
411 private boolean _validate(
412 AuthVerifierConfiguration authVerifierConfiguration) {
413
414 Properties properties = authVerifierConfiguration.getProperties();
415
416 String[] urlsIncludes = StringUtil.split(
417 properties.getProperty("urls.includes"));
418
419 if (urlsIncludes.length == 0) {
420 if (_log.isWarnEnabled()) {
421 String authVerifierClassName =
422 authVerifierConfiguration.getAuthVerifierClassName();
423
424 _log.warn(
425 "Auth verifier " + authVerifierClassName +
426 " does not have URLs configured");
427 }
428
429 return false;
430 }
431
432 return true;
433 }
434
435 }
436
437 }