/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright © 2011-2012 ForgeRock AS. All rights reserved. * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://forgerock.org/license/CDDLv1.0.html * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at http://forgerock.org/license/CDDLv1.0.html * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" */ package org.forgerock.openidm.http; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.Dictionary; import java.util.Hashtable; import java.util.Enumeration; import java.util.List; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.ConfigurationPolicy; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Reference; import org.ops4j.pax.web.extender.whiteboard.ExtenderConstants; import org.ops4j.pax.web.service.SharedWebContainerContext; import org.ops4j.pax.web.service.WebContainer; import org.osgi.framework.BundleContext; import org.osgi.service.component.ComponentContext; import org.osgi.service.http.HttpContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Http context to share amongst OpenIDM servlets to allow * for applying uniform security handling * * @author aegloff */ @Component(name = "org.forgerock.openidm.http.contextregistrator", immediate = true, policy = ConfigurationPolicy.IGNORE) public final class ContextRegistrator { final static Logger logger = LoggerFactory.getLogger(ContextRegistrator.class); @Reference WebContainer httpService; HttpContext httpContext; static ComponentContext context; List securityConfigurators = new ArrayList(); /** * Allow access for the fragments * @return bundle context if activated, null otherwise */ public static BundleContext getBundleContext() { if (context != null) { return context.getBundleContext(); } else { return null; } } @Activate protected void activate(ComponentContext context) throws Exception { this.context = context; // register the http context so other bundles can add filters etc. /*//http://team.ops4j.org/browse/PAXWEB-344 try { Method getDefaultSharedHttpContext = httpService.getClass().getDeclaredMethod("getDefaultSharedHttpContext"); if (null != getDefaultSharedHttpContext) { httpContext = (SharedWebContainerContext) getDefaultSharedHttpContext.invoke(httpService); ((SharedWebContainerContext) httpContext).registerBundle(context.getBundleContext().getBundle()); } else { httpContext = httpService.createDefaultHttpContext(); } } catch (Exception e) { httpContext = httpService.createDefaultHttpContext(); }*/ httpContext = httpService.createDefaultHttpContext(); Dictionary contextProps = new Hashtable(); contextProps.put("openidm.contextid", "shared"); contextProps.put(ExtenderConstants.PROPERTY_HTTP_CONTEXT_ID, "openidm"); //TODO: Consider the HttpContextMapping it allows to configure the path context.getBundleContext().registerService(HttpContext.class.getName(), httpContext, contextProps); logger.debug("Registered OpenIDM shared http context"); // Apply the pluggable security configurations on the httpContext initSecurityConfigurators(); activateSecurityConfigurators(context, httpContext); } @Deactivate protected void deactivate(ComponentContext context) { deactivateSecurityConfigurators(context, httpContext); } /** * Loads and instantiates the pluggable Security Configurators * * To allow for pluggability with fragments a simple convention is used * to find security configurator(s); * 1. A properties file contains a property security.configurator.class of a class in * the bundle fragment that implements SecurityConfigurator and has a no-arg constructor * 2. The properties file is name securityconfigurator.properties and placed * somewhere in the bundle or attached fragments */ private void initSecurityConfigurators() { Enumeration entries = context.getBundleContext().getBundle().findEntries("/", "*securityconfigurator.properties", true); while (entries != null && entries.hasMoreElements()) { URL entry = entries.nextElement(); logger.trace("Handle properties file at {}", entry.getPath()); InputStream is = null; java.util.Properties props = new java.util.Properties(); try { is = entry.openStream(); props.load(is); } catch (IOException ex) { logger.warn("Failed to load security extension properties file", ex); try { is.close(); } catch (Exception cex) { logger.warn("Failure during close of properties file.", cex); } } logger.trace("Loaded {}: {}", entry.getPath(), props); if (props != null) { String clazzName = (String) props.get("security.configurator.class"); logger.debug("Initiating security configurator for class: {}", clazzName); SecurityConfigurator configurator = instantiateSecurityConfigurator(clazzName); if (configurator != null) { securityConfigurators.add(configurator); } } } } /** * @param clazzName name of SecurityConfigurator to load and instantiate * @return the security configurator instance if it was successfully instantiated, null if not. * Logs any failures */ SecurityConfigurator instantiateSecurityConfigurator(String clazzName) { SecurityConfigurator configurator = null; Class configuratorClazz = null; try { configuratorClazz = context.getBundleContext().getBundle().loadClass(clazzName); logger.debug("Loaded configurator class {}", clazzName); } catch (ClassNotFoundException ex) { logger.debug("Security configurator not present: {}", clazzName); } try { if (configuratorClazz != null) { Object instance = configuratorClazz.newInstance(); logger.debug("Instantiated configurator {}", instance); configurator = (SecurityConfigurator) instance; } } catch (Exception ex) { logger.warn("Failed to load security configurator class {}", clazzName, ex); } return configurator; } /** * Activate security configurators if present to enable security * @param context the component context of the main bundle * @param httpContext the shared http context to configure */ private void activateSecurityConfigurators(ComponentContext context, HttpContext httpContext) { for (SecurityConfigurator configurator : securityConfigurators) { configurator.activate(httpService, httpContext, context); logger.info("Activated security configurator {}", configurator.getClass().getName()); } } /** * Deactivate security configurators if present to cleanup * @param context the component context of the main bundle * @param httpContext the shared http context to configure */ private void deactivateSecurityConfigurators(ComponentContext context, HttpContext httpContext) { for (SecurityConfigurator configurator : securityConfigurators) { configurator.deactivate(httpService, httpContext, context); logger.debug("Deactivated security configurator {}", configurator.getClass().getName()); } } }