Skip to content

Commit

Permalink
Have fuse example working on newest fuse 6.2. Refactoring of ServletR…
Browse files Browse the repository at this point in the history
…eregistrationService to work on fuse 6.1, 6.2 and karaf 3.0.2
  • Loading branch information
mposolda committed Jan 20, 2015
1 parent f454e5a commit 715482e
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 170 deletions.
15 changes: 14 additions & 1 deletion examples/fuse/README.md
Expand Up @@ -72,7 +72,7 @@ Securing your applications on JBoss Fuse 6.1 is a bit more tricky. There is bug
custom Jetty authenticator provided by Keycloak Jetty adapter into underlying Jetty server. Hence first step is to upgrade pax-web
version from default 3.0.6 to newer 3.1.2 . Then you need to "refresh" cxf feature too. Final step is to install "keycloak-fuse-example" feature.

All the steps could be performed with these commands in Fuse console (Replace Keycloak versions with the current version number again):
All the steps could be performed with these commands in Fuse console (Replace Keycloak versions with the current Keycloak version number):

```
features:uninstall pax-war
Expand Down Expand Up @@ -103,6 +103,19 @@ features:install keycloak-fuse-example

Now you can test example applications similarly like described for "Karaf" section.

Running example on JBoss Fuse 6.2.0
-----------------------------------
This is snapshot version of JBoss Fuse, which is not released yet at this moment. It has pax-web bug mentioned above fix already, so just those commands are
sufficient to install the demo (Replace Keycloak versions with the current Keycloak version number):

```
features:addurl mvn:org.keycloak/keycloak-osgi-features/1.1.0.Final/xml/features
features:addurl mvn:org.keycloak.example.demo/keycloak-fuse-example-features/1.1.0.Final/xml/features
features:install keycloak-fuse-example
```

Now you can test example applications similarly like described for "Karaf" section.

How to secure your own applications
-----------------------------------
Most of the steps should be understandable from testing and understanding the demo. Basically all mentioned applications require to
Expand Down
2 changes: 1 addition & 1 deletion examples/fuse/customer-app-fuse/src/main/webapp/index.html
Expand Up @@ -7,7 +7,7 @@
<body bgcolor="#E3F6CE">
<h1>Customer Portal</h1>

<p><a href="customers/cxf-ws.jsp">Customer Listing - CXF WS endpoint</a></p>
<p><a href="customers/cxf-rs.jsp">Customer Listing - CXF RS endpoint</a></p>

<p><a href="customers/camel.jsp">Admin Interface - Apache Camel endpoint</a></p>

Expand Down
12 changes: 4 additions & 8 deletions examples/fuse/cxf-jaxrs/pom.xml
Expand Up @@ -18,14 +18,10 @@
<keycloak.osgi.export>
</keycloak.osgi.export>
<keycloak.osgi.import>
META-INF.cxf,
META-INF.cxf.osgi,
org.apache.cxf.bus,
org.apache.cxf.bus.spring,
org.apache.cxf.bus.resource,
org.apache.cxf.resource,
org.apache.cxf.jaxrs,
org.apache.cxf.transport.http,
META-INF.cxf;version="[2.7,3.2)",
META-INF.cxf.osgi;version="[2.7,3.2)";resolution:=optional,
org.apache.cxf.transport.http;version="[2.7,3.2)",
org.apache.cxf.*;version="[2.7,3.2)",
org.codehaus.jackson.jaxrs;version="${jackson.version}",
org.keycloak.adapters.jetty;version="${project.version}",
org.keycloak.adapters;version="${project.version}",
Expand Down
Expand Up @@ -2,45 +2,25 @@
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd">

<!-- JAXRS Application -->

<bean id="customerBean" class="org.keycloak.example.rs.CxfCustomerService" />

<jaxrs:server id="cxfJaxrsServer" address="/customerservice">
<jaxrs:providers>
<!--<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" />-->
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</jaxrs:providers>
<jaxrs:serviceBeans>
<ref component-id="customerBean" />
</jaxrs:serviceBeans>
</jaxrs:server>

<!-- Securing of whole /cxf context by unregister default cxf servlet from paxweb and re-register with applied security constraints -->

<cm:property-placeholder persistent-id="org.apache.cxf.osgi" id="cxfOsgiPropertiesKCSecured">
<cm:default-properties>
<cm:property name="org.apache.cxf.servlet.context" value="/cxf"/>
<cm:property name="org.apache.cxf.servlet.name" value="cxf-osgi-transport-servlet"/>
<cm:property name="org.apache.cxf.servlet.hide-service-list-page" value="false"/>
<cm:property name="org.apache.cxf.servlet.disable-address-updates" value="false"/>
<cm:property name="org.apache.cxf.servlet.base-address" value=""/>
<cm:property name="org.apache.cxf.servlet.service-list-path" value=""/>
<cm:property name="org.apache.cxf.servlet.static-resources-list" value=""/>
<cm:property name="org.apache.cxf.servlet.redirects-list" value=""/>
<cm:property name="org.apache.cxf.servlet.redirect-servlet-name" value=""/>
<cm:property name="org.apache.cxf.servlet.redirect-servlet-path" value=""/>
<cm:property name="org.apache.cxf.servlet.service-list-all-contexts" value=""/>
<cm:property name="org.apache.cxf.servlet.service-list-page-authenticate" value="false"/>
<cm:property name="org.apache.cxf.servlet.service-list-page-authenticate-realm" value="karaf"/>
</cm:default-properties>
</cm:property-placeholder>
<!-- Securing of whole /cxf context by unregister default cxf servlet from paxweb and re-register with applied security constraints -->

<bean id="cxfConstraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
<property name="constraint">
Expand Down Expand Up @@ -69,38 +49,12 @@
</property>
</bean>

<bean id="defaultCxfUnregistration" class="org.keycloak.adapters.osgi.ServletUnregistrationService"
<bean id="defaultCxfReregistration" class="org.keycloak.adapters.osgi.ServletReregistrationService" depends-on="cxfKeycloakPaxWebIntegration"
init-method="start" destroy-method="stop">
<property name="bundleContext" ref="blueprintBundleContext" />
<property name="servletReference">
<reference interface="javax.servlet.Servlet" component-name="osgiServlet" />
<reference interface="javax.servlet.Servlet" filter="(alias=/cxf)" timeout="5000" />
</property>
</bean>

<bean id="osgiServletKCSecured" class="org.apache.cxf.transport.servlet.CXFNonSpringServlet" depends-on="cxfKeycloakPaxWebIntegration defaultCxfUnregistration">
<argument>
<reference interface="org.apache.cxf.transport.http.DestinationRegistry" timeout="5000"/>
</argument>
<argument value="false"/>
</bean>

<service ref="osgiServletKCSecured" interface="javax.servlet.Servlet">
<service-properties>
<entry key="alias" value="${org.apache.cxf.servlet.context}"/>
<entry key="servlet-name" value="${org.apache.cxf.servlet.name}"/>
<entry key="hide-service-list-page" value="${org.apache.cxf.servlet.hide-service-list-page}"/>
<entry key="disable-address-updates" value="${org.apache.cxf.servlet.disable-address-updates}"/>
<entry key="base-address" value="${org.apache.cxf.servlet.base-address}"/>
<entry key="service-list-path" value="${org.apache.cxf.servlet.service-list-path}"/>
<entry key="static-resources-list" value="${org.apache.cxf.servlet.static-resources-list}"/>
<entry key="redirects-list" value="${org.apache.cxf.servlet.redirects-list}"/>
<entry key="redirect-servlet-name" value="${org.apache.cxf.servlet.redirect-servlet-name}"/>
<entry key="redirect-servlet-path" value="${org.apache.cxf.servlet.redirect-servlet-path}"/>
<entry key="service-list-all-contexts" value="${org.apache.cxf.servlet.service-list-all-contexts}"/>
<entry key="service-list-page-authenticate" value="${org.apache.cxf.servlet.service-list-page-authenticate}"/>
<entry key="service-list-page-authenticate-realm" value="${org.apache.cxf.servlet.service-list-page-authenticate-realm}"/>
</service-properties>
</service>


</blueprint>
16 changes: 7 additions & 9 deletions examples/fuse/cxf-jaxws/pom.xml
Expand Up @@ -25,15 +25,13 @@
javax.xml.bind.annotation,
javax.xml.namespace,
javax.xml.ws,
META-INF.cxf,
META-INF.cxf.osgi,
org.apache.cxf.bus,
org.apache.cxf.bus.spring,
org.apache.cxf.bus.resource,
org.apache.cxf.configuration.spring,
org.apache.cxf.resource,
org.apache.cxf.jaxws,
org.apache.cxf.transport.http,
META-INF.cxf;version="[2.7,3.2)",
META-INF.cxf.osgi;version="[2.7,3.2)";resolution:=optional,
org.apache.cxf.bus;version="[2.7,3.2)",
org.apache.cxf.bus.spring;version="[2.7,3.2)",
org.apache.cxf.bus.resource;version="[2.7,3.2)",
org.apache.cxf.transport.http;version="[2.7,3.2)",
org.apache.cxf.*;version="[2.7,3.2)",
org.springframework.beans.factory.config,
*;resolution:=optional
</keycloak.osgi.import>
Expand Down
4 changes: 3 additions & 1 deletion examples/fuse/product-app-fuse/pom.xml
Expand Up @@ -19,8 +19,11 @@
<keycloak.osgi.export>
</keycloak.osgi.export>
<keycloak.osgi.import>
javax.xml.namespace,
org.eclipse.jetty.security;version="[8.1,10)",
org.eclipse.jetty.util.security;version="[8.1,10)",
org.apache.cxf.service.model;version="[2.7,3.2)",
org.apache.cxf.*;version="[2.7,3.2)",
org.keycloak.adapters.jetty;version="${project.version}",
org.keycloak.*;version="${project.version}",
*;resolution:=optional
Expand Down Expand Up @@ -72,7 +75,6 @@
<Import-Package>${keycloak.osgi.import}</Import-Package>
<Private-Package>${keycloak.osgi.private}</Private-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package>
<Require-Bundle>org.apache.cxf.bundle</Require-Bundle>
</instructions>
</configuration>
</plugin>
Expand Down
@@ -0,0 +1,152 @@
package org.keycloak.adapters.osgi;

import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;

import javax.servlet.Servlet;

import org.jboss.logging.Logger;
import org.ops4j.pax.web.service.WebContainer;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

/**
* Service, which allows to remove previously registered servlets in karaf/fuse environment. It assumes that particular servlet was previously
* registered as service in OSGI container under {@link javax.servlet.Servlet} interface.
*
* <p>The point is to register automatically registered builtin servlet endpoints (like "/cxf" for instance) to allow secure them
* by Keycloak and re-register them again</p>
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ServletReregistrationService {

protected static final Logger log = Logger.getLogger(ServletReregistrationService.class);

private static final List<String> FILTERED_PROPERTIES = Arrays.asList("objectClass", "service.id");

private BundleContext bundleContext;
private ServiceReference servletReference;
private ServiceTracker webContainerTracker;

public BundleContext getBundleContext() {
return bundleContext;
}

public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}

public ServiceReference getServletReference() {
return servletReference;
}

public void setServletReference(ServiceReference servletReference) {
this.servletReference = servletReference;
}

protected ServiceTracker getWebContainerTracker() {
return webContainerTracker;
}

public void start() {
if (servletReference == null) {
throw new IllegalStateException("No servlet reference provided");
}

final Servlet servlet = (Servlet) bundleContext.getService(servletReference);
WebContainer externalWebContainer = findExternalWebContainer();
if (externalWebContainer == null) {
return;
}

// Unregister servlet from external container now
try {
externalWebContainer.unregisterServlet(servlet);
log.debug("Original servlet with alias " + getAlias() + " unregistered successfully from external web container.");
} catch (IllegalStateException e) {
log.warn("Can't unregister servlet due to: " + e.getMessage());
}

ServiceTrackerCustomizer trackerCustomizer = new ServiceTrackerCustomizer() {

@Override
public Object addingService(ServiceReference webContainerServiceReference) {
WebContainer ourWebContainer = (WebContainer) bundleContext.getService(webContainerServiceReference);
registerServlet(ourWebContainer, servlet);
log.debugv("Servlet with alias " + getAlias() + " registered to secured web container");
return ourWebContainer;
}

@Override
public void modifiedService(ServiceReference reference, Object service) {
}

@Override
public void removedService(ServiceReference webContainerServiceReference, Object service) {
WebContainer ourWebContainer = (WebContainer) bundleContext.getService(webContainerServiceReference);
String alias = getAlias();
ourWebContainer.unregister(alias);
log.debug("Servlet with alias " + getAlias() + " unregistered from secured web container");
}
};

webContainerTracker = new ServiceTracker(bundleContext, WebContainer.class.getName(), trackerCustomizer);
webContainerTracker.open();
}

public void stop() {
// Stop tracking our container now and removing reference. This should unregister servlet from our container via trackerCustomizer.removedService (if it's not already unregistered)
webContainerTracker.remove(webContainerTracker.getServiceReference());

// Re-register servlet back to original context
WebContainer externalWebContainer = findExternalWebContainer();
Servlet servlet = (Servlet) bundleContext.getService(servletReference);
registerServlet(externalWebContainer, servlet);
log.debug("Servlet with alias " + getAlias() + " registered back to external web container");
}

private String getAlias() {
return (String) servletReference.getProperty("alias");
}

protected void registerServlet(WebContainer webContainer, Servlet servlet) {
try {
Hashtable<String, Object> servletInitParams = new Hashtable<String, Object>();
String[] propNames = servletReference.getPropertyKeys();
for (String propName : propNames) {
if (!FILTERED_PROPERTIES.contains(propName)) {
servletInitParams.put(propName, servletReference.getProperty(propName));
}
}

// Try to register servlet in given web container now
HttpContext httpContext = webContainer.createDefaultHttpContext();
String alias = (String) servletReference.getProperty("alias");
webContainer.registerServlet(alias, servlet, servletInitParams, httpContext);
} catch (Exception e) {
log.error("Can't register servlet in web container", e);
}
}

/**
* Find web container in the bundle, where was servlet originally registered
*
* @return web container or null
*/
protected WebContainer findExternalWebContainer() {
BundleContext servletBundleContext = servletReference.getBundle().getBundleContext();
ServiceReference webContainerReference = servletBundleContext.getServiceReference(WebContainer.class.getName());
if (webContainerReference == null) {
log.warn("Not found webContainer reference for bundle " + servletBundleContext);
return null;
} else {
return (WebContainer) servletBundleContext.getService(webContainerReference);
}
}

}

0 comments on commit 715482e

Please sign in to comment.