/**
* 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.remote.http.tunnel.extender.internal;
import com.liferay.osgi.felix.util.AbstractExtender;
import com.liferay.portal.configuration.metatype.bnd.util.ConfigurableUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.remote.http.tunnel.extender.configuration.HttpTunnelExtenderConfiguration;
import com.liferay.portal.servlet.TunnelServlet;
import com.liferay.portal.servlet.filters.authverifier.AuthVerifierFilter;
import java.net.URL;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import org.apache.felix.utils.extender.Extension;
import org.apache.felix.utils.log.Logger;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.http.context.ServletContextHelper;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
/**
* @author Miguel Pastor
*/
@Component(
configurationPid = "com.liferay.portal.remote.http.tunnel.configuration.HttpTunnelExtenderConfiguration",
configurationPolicy = ConfigurationPolicy.REQUIRE, immediate = true
)
public class HttpTunnelExtender extends AbstractExtender {
@Activate
protected void activate(
BundleContext bundleContext, Map<String, Object> properties)
throws Exception {
_httpTunnelExtenderConfiguration = ConfigurableUtil.createConfigurable(
HttpTunnelExtenderConfiguration.class, properties);
_logger = new Logger(bundleContext);
start(bundleContext);
}
@Deactivate
protected void deactivate(BundleContext bundleContext) throws Exception {
stop(bundleContext);
}
@Override
protected void debug(Bundle bundle, String s) {
_logger.log(Logger.LOG_DEBUG, "[" + bundle + "] " + s);
}
@Override
protected Extension doCreateExtension(Bundle bundle) throws Exception {
Dictionary<String, String> headers = bundle.getHeaders();
if (headers.get("Http-Tunnel") == null) {
return null;
}
return new TunnelServletExtension(bundle);
}
@Override
protected void error(String s, Throwable t) {
_logger.log(Logger.LOG_ERROR, s, t);
}
@Modified
protected void modified(
BundleContext bundleContext, Map<String, Object> properties)
throws Exception {
deactivate(bundleContext);
activate(bundleContext, properties);
}
@Override
protected void warn(Bundle bundle, String s, Throwable t) {
_logger.log(Logger.LOG_WARNING, "[" + bundle + "] " + s, t);
}
private HttpTunnelExtenderConfiguration _httpTunnelExtenderConfiguration;
private Logger _logger;
private final class ServiceRegistrations {
public ServiceRegistrations(
ServiceRegistration<Filter> authVerifierFilterServiceRegistration,
ServiceRegistration<ServletContextHelper>
servletContextHelperServiceRegistration,
ServiceRegistration<Servlet> tunneServletServiceRegistration) {
_authVerifierFilterServiceRegistration =
authVerifierFilterServiceRegistration;
_servletContextHelperServiceRegistration =
servletContextHelperServiceRegistration;
_tunnelServletServiceRegistration = tunneServletServiceRegistration;
}
private final ServiceRegistration<Filter>
_authVerifierFilterServiceRegistration;
private final ServiceRegistration<ServletContextHelper>
_servletContextHelperServiceRegistration;
private final ServiceRegistration<Servlet>
_tunnelServletServiceRegistration;
}
private class TunnelServletExtension implements Extension {
public TunnelServletExtension(Bundle bundle) {
_bundle = bundle;
}
@Override
public void destroy() throws Exception {
ServiceRegistration<Filter> authVerifierFilterServiceRegistration =
_serviceRegistrations._authVerifierFilterServiceRegistration;
authVerifierFilterServiceRegistration.unregister();
ServiceRegistration<ServletContextHelper>
servletContextHelperServiceRegistration =
_serviceRegistrations.
_servletContextHelperServiceRegistration;
servletContextHelperServiceRegistration.unregister();
ServiceRegistration<Servlet> tunnelServletServiceRegistration =
_serviceRegistrations._tunnelServletServiceRegistration;
tunnelServletServiceRegistration.unregister();
}
@Override
public void start() throws Exception {
BundleContext bundleContext = _bundle.getBundleContext();
Dictionary<String, Object> properties = new Hashtable<>();
properties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT,
"liferay.http.tunnel." + _bundle.getSymbolicName());
properties.put(
HttpWhiteboardConstants.
HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX +
"auth.verifier.TunnelingServletAuthVerifier.hosts." +
"allowed",
StringUtil.merge(
_httpTunnelExtenderConfiguration.hostsAllowed()));
properties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_NAME,
AuthVerifierFilter.class.getName());
properties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN,
"/api/liferay/do");
ServiceRegistration<Filter> authVerifierFilterServiceRegistration =
bundleContext.registerService(
Filter.class, new AuthVerifierFilter(), properties);
properties = new Hashtable<>();
properties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME,
"liferay.http.tunnel." + _bundle.getSymbolicName());
properties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH,
"/" + _bundle.getSymbolicName());
ServiceRegistration<ServletContextHelper>
servletContextHelperServiceRegistration =
bundleContext.registerService(
ServletContextHelper.class,
new ServletContextHelper(_bundle) {
@Override
public URL getResource(String name) {
if (name.startsWith("/")) {
name = name.substring(1);
}
return _bundle.getResource(name);
}
},
properties);
properties = new Hashtable<>();
properties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT,
"liferay.http.tunnel." + _bundle.getSymbolicName());
properties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME,
TunnelServlet.class.getName());
properties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN,
"/api/liferay/do");
properties.put("servlet.init.httpMethods", "POST");
ServiceRegistration<Servlet> tunnelServletServiceRegistration =
bundleContext.registerService(
Servlet.class, new TunnelServlet(), properties);
_serviceRegistrations = new ServiceRegistrations(
authVerifierFilterServiceRegistration,
servletContextHelperServiceRegistration,
tunnelServletServiceRegistration);
}
private final Bundle _bundle;
private ServiceRegistrations _serviceRegistrations;
}
}