Have fuse example working on newest fuse 6.2. Refactoring of ServletReregistrationService to work on fuse 6.1, 6.2 and karaf 3.0.2
This commit is contained in:
parent
f454e5ae12
commit
715482e371
9 changed files with 185 additions and 170 deletions
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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}",
|
||||
|
|
|
@ -2,11 +2,9 @@
|
|||
<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 -->
|
||||
|
||||
|
@ -14,7 +12,6 @@
|
|||
|
||||
<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>
|
||||
|
@ -22,25 +19,8 @@
|
|||
</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">
|
||||
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
package org.keycloak.adapters.osgi;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 ServletUnregistrationService {
|
||||
|
||||
protected static final Logger log = Logger.getLogger(ServletUnregistrationService.class);
|
||||
|
||||
private BundleContext bundleContext;
|
||||
private ServiceReference servletReference;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: Re-register original servlet back during stop?
|
||||
public void start() {
|
||||
if (servletReference == null) {
|
||||
throw new IllegalStateException("No servlet reference provided");
|
||||
}
|
||||
|
||||
Servlet servlet = (Servlet) bundleContext.getService(servletReference);
|
||||
WebContainer webContainer = findWebContainer(servletReference);
|
||||
if (webContainer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unregister servlet now
|
||||
try {
|
||||
webContainer.unregisterServlet(servlet);
|
||||
log.debugv("Original servlet with alias " + servletReference.getProperty("alias") + " unregistered successfully.");
|
||||
} catch (IllegalStateException e) {
|
||||
log.warnv("Can't unregister servlet due to: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
try {
|
||||
Servlet servlet = (Servlet) bundleContext.getService(servletReference);
|
||||
WebContainer webContainer = findWebContainer(servletReference);
|
||||
if (webContainer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Hashtable<String, Object> servletInitParams = new Hashtable<String, Object>();
|
||||
String[] propNames = servletReference.getPropertyKeys();
|
||||
for (String propName : propNames) {
|
||||
servletInitParams.put(propName, servletReference.getProperty(propName));
|
||||
}
|
||||
|
||||
// Try to register original servlet back
|
||||
HttpContext httpContext = webContainer.createDefaultHttpContext();
|
||||
String alias = (String) servletReference.getProperty("alias");
|
||||
webContainer.registerServlet(alias, servlet, servletInitParams, httpContext);
|
||||
} catch (Exception e) {
|
||||
log.warn("Can't register original servlet back", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected WebContainer findWebContainer(ServiceReference servletRef) {
|
||||
BundleContext servletBundleContext = servletRef.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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue