/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.osgi.web.servlet.context.helper.internal; import com.liferay.osgi.util.BundleUtil; import com.liferay.portal.kernel.util.CharPool; import com.liferay.portal.kernel.util.ListUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.osgi.web.servlet.context.helper.definition.WebResourceCollectionDefinition; import com.liferay.portal.servlet.delegate.ServletContextDelegate; import java.io.IOException; import java.net.URL; import java.util.Enumeration; import java.util.List; import java.util.Objects; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.felix.utils.log.Logger; import org.osgi.framework.Bundle; import org.osgi.service.http.context.ServletContextHelper; /** * @author Raymond Augé */ public class CustomServletContextHelper extends ServletContextHelper implements ServletContextListener { public CustomServletContextHelper( Bundle bundle, Logger logger, List<WebResourceCollectionDefinition> webResourceCollectionDefinitions) { super(bundle); _bundle = bundle; _logger = logger; _webResourceCollectionDefinitions = webResourceCollectionDefinitions; Class<?> clazz = getClass(); _string = clazz.getSimpleName() + '[' + bundle + ']'; } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { _servletContext = null; } @Override public void contextInitialized(ServletContextEvent servletContextEvent) { _servletContext = ServletContextDelegate.create( servletContextEvent.getServletContext()); } @Override public String getRealPath(String path) { return null; } @Override public URL getResource(String name) { if ((name == null) || name.contains("*")) { return null; } if (name.isEmpty()) { name = StringPool.SLASH; } else if (name.charAt(0) != CharPool.SLASH) { name = StringPool.SLASH.concat(name); } URL url = BundleUtil.getResourceInBundleOrFragments(_bundle, name); if (url == null) { url = BundleUtil.getResourceInBundleOrFragments( _bundle, "/META-INF/resources" + name); } if (url == null) { try { Enumeration<URL> enumeration = _bundle.getResources( "/META-INF/resources" + name); if ((enumeration != null) && enumeration.hasMoreElements()) { url = enumeration.nextElement(); } } catch (IOException ioe) { _logger.log( Logger.LOG_ERROR, "Unable to get resource name " + name + " on bundle " + _bundle, ioe); } } return url; } public ServletContext getServletContext() { return _servletContext; } @Override public boolean handleSecurity( HttpServletRequest request, HttpServletResponse response) { String path = null; if (request.getDispatcherType() == DispatcherType.INCLUDE) { String pathInfo = (String)request.getAttribute( RequestDispatcher.INCLUDE_PATH_INFO); path = pathInfo; } else { path = request.getPathInfo(); } if (path == null) { return true; } if (path.indexOf('/') != 0) { path = '/' + path; } if (path.startsWith("/META-INF/") || path.startsWith("/OSGI-INF/") || path.startsWith("/OSGI-OPT/") || path.startsWith("/WEB-INF/")) { return sendErrorForbidden(request, response, path); } if (ListUtil.isEmpty(_webResourceCollectionDefinitions)) { return true; } for (WebResourceCollectionDefinition webResourceCollectionDefinition : _webResourceCollectionDefinitions) { boolean forbidden = false; for (String urlPattern : webResourceCollectionDefinition.getUrlPatterns()) { // Servlet 3 spec 12.2 if (urlPattern.startsWith("*.")) { String patternExtension = urlPattern.substring(2); if (Validator.isNotNull(patternExtension) && Objects.equals("*", patternExtension)) { forbidden = true; break; } int index = path.lastIndexOf("."); String pathExtension = path.substring(index + 1); if (Objects.equals(patternExtension, pathExtension)) { forbidden = true; break; } } else if (urlPattern.endsWith("/*")) { if (urlPattern.equals("/*")) { forbidden = true; break; } String subpath = path; String urlPatternPath = urlPattern.substring( 0, urlPattern.indexOf("/*") + 1); int index = subpath.lastIndexOf("/"); if (index > 0) { subpath = subpath.substring(0, index + 1); } if (Objects.equals(urlPatternPath, subpath)) { forbidden = true; break; } } else if (Objects.equals(urlPattern, path)) { forbidden = true; break; } } if (forbidden) { // Servlet 3 spec 13.8.1 List<String> httpMethods = webResourceCollectionDefinition.getHttpMethods(); if (ListUtil.isNotEmpty(httpMethods) && !httpMethods.contains(request.getMethod())) { forbidden = false; } List<String> httpMethodExceptions = webResourceCollectionDefinition.getHttpMethodExceptions(); if (ListUtil.isNotEmpty(httpMethodExceptions) && httpMethodExceptions.contains(request.getMethod())) { forbidden = false; } } if (forbidden) { return sendErrorForbidden(request, response, path); } } return true; } @Override public String toString() { return _string; } protected boolean sendErrorForbidden( HttpServletRequest request, HttpServletResponse response, String path) { try { ServletContext servletContext = request.getServletContext(); servletContext.log( "[WAB ERROR] Attempt to load illegal path " + path + " in " + toString()); response.sendError(HttpServletResponse.SC_FORBIDDEN, path); } catch (IOException ioe) { response.setStatus(HttpServletResponse.SC_FORBIDDEN); } return false; } private final Bundle _bundle; private final Logger _logger; private ServletContext _servletContext; private final String _string; private final List<WebResourceCollectionDefinition> _webResourceCollectionDefinitions; }