/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 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.net.URL; import java.util.ArrayList; import java.util.Dictionary; import java.util.Enumeration; import java.util.Hashtable; 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.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 * */ @Component(name = "org.forgerock.openidm.http.context", immediate = true, policy = ConfigurationPolicy.IGNORE) public final class ContextRegistrator { final static Logger logger = LoggerFactory.getLogger(ContextRegistrator.class); public static final String OPENIDM = "openidm"; @Reference private WebContainer httpService; HttpContext httpContext; static ComponentContext context; List<SecurityConfigurator> securityConfigurators = new ArrayList<SecurityConfigurator>(); /** * 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 { ContextRegistrator.context = context; httpContext = httpService.createDefaultHttpContext(); Dictionary<String, Object> contextProps = new Hashtable<String, Object>(); contextProps.put("openidm.contextid", "shared"); // 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 <prefix>securityconfigurator.properties and * placed somewhere in the bundle or attached fragments */ private void initSecurityConfigurators() { Enumeration<URL> 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()); } } public String getHttpContextId() { return OPENIDM; } }