001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.security.auth;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.util.InstanceFactory;
022    import com.liferay.portal.kernel.util.PropsKeys;
023    import com.liferay.portal.kernel.util.PropsUtil;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.service.UserLocalServiceUtil;
027    import com.liferay.portal.util.ClassLoaderUtil;
028    import com.liferay.portal.util.PortalUtil;
029    import com.liferay.portal.util.PropsValues;
030    
031    import java.util.ArrayList;
032    import java.util.HashMap;
033    import java.util.Iterator;
034    import java.util.List;
035    import java.util.Map;
036    import java.util.Properties;
037    import java.util.Set;
038    import java.util.concurrent.CopyOnWriteArrayList;
039    
040    import javax.servlet.http.HttpServletRequest;
041    
042    import jodd.util.Wildcard;
043    
044    /**
045     * @author Tomas Polesovsky
046     */
047    public class AuthVerifierPipeline {
048    
049            public static final String AUTH_TYPE = "auth.type";
050    
051            public static String getAuthVerifierPropertyName(String className) {
052                    String simpleClassName = StringUtil.extractLast(
053                            className, StringPool.PERIOD);
054    
055                    return PropsKeys.AUTH_VERIFIER.concat(simpleClassName).concat(
056                            StringPool.PERIOD);
057            }
058    
059            public static void register(
060                    AuthVerifierConfiguration authVerifierConfiguration) {
061    
062                    _instance._register(authVerifierConfiguration);
063            }
064    
065            public static void unregister(
066                    AuthVerifierConfiguration authVerifierConfiguration) {
067    
068                    _instance._unregister(authVerifierConfiguration);
069            }
070    
071            public static AuthVerifierResult verifyRequest(
072                            AccessControlContext accessControlContext)
073                    throws PortalException, SystemException {
074    
075                    return _instance._verifyRequest(accessControlContext);
076            }
077    
078            private AuthVerifierPipeline() {
079                    _initAuthVerifierConfigurations();
080            }
081    
082            private AuthVerifierResult _createGuestVerificationResult(
083                            AccessControlContext accessControlContext)
084                    throws PortalException, SystemException {
085    
086                    AuthVerifierResult authVerifierResult = new AuthVerifierResult();
087    
088                    authVerifierResult.setState(AuthVerifierResult.State.SUCCESS);
089    
090                    HttpServletRequest request = accessControlContext.getRequest();
091    
092                    long companyId = PortalUtil.getCompanyId(request);
093    
094                    long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
095    
096                    authVerifierResult.setUserId(defaultUserId);
097    
098                    return authVerifierResult;
099            }
100    
101            private List<AuthVerifierConfiguration> _getAuthVerifierConfigurations(
102                    AccessControlContext accessControlContext) {
103    
104                    HttpServletRequest request = accessControlContext.getRequest();
105    
106                    List<AuthVerifierConfiguration> authVerifierConfigurations =
107                            new ArrayList<AuthVerifierConfiguration>();
108    
109                    String requestURI = request.getRequestURI();
110    
111                    String contextPath = request.getContextPath();
112    
113                    requestURI = requestURI.substring(contextPath.length());
114    
115                    for (AuthVerifierConfiguration authVerifierConfiguration :
116                                    _authVerifierConfigurations) {
117    
118                            authVerifierConfiguration = _mergeAuthVerifierConfiguration(
119                                    authVerifierConfiguration, accessControlContext);
120    
121                            if (_isMatchingRequestURI(authVerifierConfiguration, requestURI)) {
122                                    authVerifierConfigurations.add(authVerifierConfiguration);
123                            }
124                    }
125    
126                    return authVerifierConfigurations;
127            }
128    
129            private void _initAuthVerifierConfigurations() {
130                    _authVerifierConfigurations =
131                            new CopyOnWriteArrayList<AuthVerifierConfiguration>();
132    
133                    for (String authVerifierClassName :
134                                    PropsValues.AUTH_VERIFIER_PIPELINE) {
135    
136                            try {
137                                    AuthVerifierConfiguration authVerifierConfiguration =
138                                            new AuthVerifierConfiguration();
139    
140                                    AuthVerifier authVerifier =
141                                            (AuthVerifier)InstanceFactory.newInstance(
142                                                    ClassLoaderUtil.getPortalClassLoader(),
143                                                    authVerifierClassName);
144    
145                                    authVerifierConfiguration.setAuthVerifier(authVerifier);
146    
147                                    authVerifierConfiguration.setAuthVerifierClassName(
148                                            authVerifierClassName);
149    
150                                    Properties properties = PropsUtil.getProperties(
151                                            getAuthVerifierPropertyName(authVerifierClassName), true);
152    
153                                    authVerifierConfiguration.setProperties(properties);
154    
155                                    _authVerifierConfigurations.add(authVerifierConfiguration);
156                            }
157                            catch (Exception e) {
158                                    _log.error("Unable to initialize " + authVerifierClassName, e);
159                            }
160                    }
161            }
162    
163            private boolean _isMatchingRequestURI(
164                    AuthVerifierConfiguration authVerifierConfiguration,
165                    String requestURI) {
166    
167                    AuthVerifier authVerifier = authVerifierConfiguration.getAuthVerifier();
168    
169                    Properties properties = authVerifierConfiguration.getProperties();
170    
171                    String[] urlsExcludes = StringUtil.split(
172                            properties.getProperty("urls.excludes"));
173    
174                    if ((urlsExcludes.length > 0) &&
175                            (Wildcard.matchOne(requestURI, urlsExcludes) > -1)) {
176    
177                            return false;
178                    }
179    
180                    String[] urlsIncludes = StringUtil.split(
181                            properties.getProperty("urls.includes"));
182    
183                    if (urlsIncludes.length == 0) {
184                            Class<?> authVerifierClass = authVerifier.getClass();
185    
186                            _log.error(
187                                    "Auth verifier " + authVerifierClass.getName() +
188                                            " does not have any URLs configured");
189    
190                            return false;
191                    }
192    
193                    return Wildcard.matchOne(requestURI, urlsIncludes) > -1;
194            }
195    
196            private AuthVerifierConfiguration _mergeAuthVerifierConfiguration(
197                    AuthVerifierConfiguration authVerifierConfiguration,
198                    AccessControlContext accessControlContext) {
199    
200                    Map<String, Object> settings = accessControlContext.getSettings();
201    
202                    String authVerifierSettingsKey = getAuthVerifierPropertyName(
203                            authVerifierConfiguration.getAuthVerifierClassName());
204    
205                    boolean merge = false;
206    
207                    Set<String> settingsKeys = settings.keySet();
208    
209                    Iterator<String> iterator = settingsKeys.iterator();
210    
211                    while (iterator.hasNext() && !merge) {
212                            String settingsKey = iterator.next();
213    
214                            if (settingsKey.startsWith(authVerifierSettingsKey)) {
215                                    if (settings.get(settingsKey) instanceof String) {
216                                            merge = true;
217                                    }
218                            }
219                    }
220    
221                    if (!merge) {
222                            return authVerifierConfiguration;
223                    }
224    
225                    AuthVerifierConfiguration mergedAuthVerifierConfiguration =
226                            new AuthVerifierConfiguration();
227    
228                    mergedAuthVerifierConfiguration.setAuthVerifier(
229                            authVerifierConfiguration.getAuthVerifier());
230    
231                    Properties mergedProperties = new Properties(
232                            authVerifierConfiguration.getProperties());
233    
234                    for (String settingsKey : settings.keySet()) {
235                            if (settingsKey.startsWith(authVerifierSettingsKey)) {
236                                    Object settingsValue = settings.get(settingsKey);
237    
238                                    if (settingsValue instanceof String) {
239                                            String propertiesKey = settingsKey.substring(
240                                                    authVerifierSettingsKey.length());
241    
242                                            mergedProperties.setProperty(
243                                                    propertiesKey, (String)settingsValue);
244                                    }
245                            }
246                    }
247    
248                    mergedAuthVerifierConfiguration.setProperties(mergedProperties);
249    
250                    return mergedAuthVerifierConfiguration;
251            }
252    
253            private Map<String, Object> _mergeSettings(
254                    Properties properties, Map<String, Object> settings) {
255    
256                    Map<String, Object> mergedSettings = new HashMap<String, Object>(
257                            settings);
258    
259                    if (properties != null) {
260                            for (Map.Entry<Object, Object> entry : properties.entrySet()) {
261                                    mergedSettings.put((String)entry.getKey(), entry.getValue());
262                            }
263                    }
264    
265                    return mergedSettings;
266            }
267    
268            private void _register(
269                    AuthVerifierConfiguration authVerifierConfiguration) {
270    
271                    if (authVerifierConfiguration == null) {
272                            throw new IllegalArgumentException(
273                                    "Auth verifier configuration is null");
274                    }
275    
276                    if (authVerifierConfiguration.getAuthVerifier() == null) {
277                            throw new IllegalArgumentException("Auth verifier is null");
278                    }
279    
280                    if (authVerifierConfiguration.getAuthVerifierClassName() == null) {
281                            throw new IllegalArgumentException("Class name is null");
282                    }
283    
284                    if (authVerifierConfiguration.getProperties() == null) {
285                            throw new IllegalArgumentException("Properties is null");
286                    }
287    
288                    _authVerifierConfigurations.add(0, authVerifierConfiguration);
289            }
290    
291            private void _unregister(
292                    AuthVerifierConfiguration authVerifierConfiguration) {
293    
294                    if (authVerifierConfiguration == null) {
295                            throw new IllegalArgumentException(
296                                    "Auth verifier configuration is null");
297                    }
298    
299                    _authVerifierConfigurations.remove(authVerifierConfiguration);
300            }
301    
302            private AuthVerifierResult _verifyRequest(
303                            AccessControlContext accessControlContext)
304                    throws PortalException, SystemException {
305    
306                    if (accessControlContext == null) {
307                            throw new IllegalArgumentException(
308                                    "Access control context is null");
309                    }
310    
311                    List<AuthVerifierConfiguration> authVerifierConfigurations =
312                            _getAuthVerifierConfigurations(accessControlContext);
313    
314                    for (AuthVerifierConfiguration authVerifierConfiguration :
315                                    authVerifierConfigurations) {
316    
317                            AuthVerifierResult authVerifierResult = null;
318    
319                            AuthVerifier authVerifier =
320                                    authVerifierConfiguration.getAuthVerifier();
321    
322                            Properties properties = authVerifierConfiguration.getProperties();
323    
324                            try {
325                                    authVerifierResult = authVerifier.verify(
326                                            accessControlContext, properties);
327                            }
328                            catch (Exception e) {
329                                    if (_log.isDebugEnabled()) {
330                                            Class<?> authVerifierClass = authVerifier.getClass();
331    
332                                            _log.debug("Skipping " + authVerifierClass.getName(), e);
333                                    }
334    
335                                    continue;
336                            }
337    
338                            if (authVerifierResult == null) {
339                                    Class<?> authVerifierClass = authVerifier.getClass();
340    
341                                    _log.error(
342                                            "Auth verifier " + authVerifierClass.getName() +
343                                                    " did not return an auth verifier result");
344    
345                                    continue;
346                            }
347    
348                            if (authVerifierResult.getState() !=
349                                            AuthVerifierResult.State.NOT_APPLICABLE) {
350    
351                                    Map<String, Object> settings = _mergeSettings(
352                                            properties, authVerifierResult.getSettings());
353    
354                                    settings.put(AUTH_TYPE, authVerifier.getAuthType());
355    
356                                    authVerifierResult.setSettings(settings);
357    
358                                    return authVerifierResult;
359                            }
360                    }
361    
362                    return _createGuestVerificationResult(accessControlContext);
363            }
364    
365            private static Log _log = LogFactoryUtil.getLog(AuthVerifierPipeline.class);
366    
367            private static AuthVerifierPipeline _instance = new AuthVerifierPipeline();
368    
369            private List<AuthVerifierConfiguration> _authVerifierConfigurations;
370    
371    }