Permalink
Browse files

SWARM-123 - Provide extra configuration for Jolokia (#134)

Motivation
----------

Particularly when running Jolokia within the context of a Keycloak-enabled
application, it would be fantastic to be able to also secure the Jolokia
endpoints with Keycloak.

Modifications
-------------

If org.wildfly.swarm:keycloak is present in a -swarm.jar, AND a property
named swarm.jolokia.keycloak.role is set to non-null, then the jolokia.war
is manipulated akin to:

    jolokiaWar.as(Secured.class).protect().withRole( THE_ROLE );

Result
------

In the event Keycloak is available, and a property/config-value is set,
then Jolokia endpoints can be easily secured using the underlying Keycloak
infrastructure.
  • Loading branch information...
bobmcwhirter authored and kenfinnigan committed Sep 12, 2016
1 parent cf3e7e3 commit ac18d970d681ca9ba021a6b10df381c590b86df1
@@ -0,0 +1,27 @@
package org.wildfly.swarm;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.jboss.shrinkwrap.api.Archive;
import org.wildfly.swarm.spi.api.JARArchive;
import org.wildfly.swarm.spi.api.JBossDeploymentStructureAsset;
import org.wildfly.swarm.spi.api.JBossDeploymentStructureContainer;
/**
* @author Bob McWhirter
*/
public class DebugUtils {
public static void dumpJBossDeploymentStructure(Archive archive) {
System.err.println( "--- start jboss-deployment-structure.xml" );
JBossDeploymentStructureAsset asset = archive.as(JARArchive.class).getDescriptorAsset();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(asset.openStream()))) {
reader.lines().forEach(line -> System.err.println(line));
} catch (IOException e) {
e.printStackTrace();
}
System.err.println( "--- end jboss-deployment-structure.xml" );
}
}
@@ -1,2 +1,4 @@
org.wildfly.swarm.undertow
org.jboss.as.logging
*org.wildfly.swarm.keycloak
@@ -36,6 +36,12 @@
<artifactId>spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>keycloak</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jboss</groupId>
<artifactId>staxmapper</artifactId>
@@ -7,4 +7,5 @@
String CONTEXT = "swarm.jolokia.context";
String ACCESS_XML = "swarm.jolokia.access.xml";
String KEYCLOAK_ROLE = "swarm.jolokia.keycloak.role";
}
@@ -0,0 +1,56 @@
package org.wildfly.swarm.jolokia.runtime;
import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jboss.shrinkwrap.api.Archive;
import org.wildfly.swarm.jolokia.JolokiaFraction;
import org.wildfly.swarm.jolokia.JolokiaProperties;
import org.wildfly.swarm.keycloak.KeycloakFraction;
import org.wildfly.swarm.keycloak.Secured;
import org.wildfly.swarm.spi.api.Customizer;
import org.wildfly.swarm.spi.runtime.annotations.ConfigurationValue;
import org.wildfly.swarm.spi.runtime.annotations.Pre;
/**
* @author Bob McWhirter
*/
@Pre
@Singleton
public class JolokiaKeycloakCustomizer implements Customizer {
@Inject
KeycloakFraction keycloak;
@Inject
JolokiaFraction jolokia;
@Inject
@ConfigurationValue(JolokiaProperties.KEYCLOAK_ROLE)
String role;
@Override
public void customize() {
if ( this.role == null ) {
return;
}
Consumer<Archive> keycloakPreparer = (archive)->{
archive.as(Secured.class)
.protect()
.withRole(this.role);
};
Consumer<Archive> preparer = this.jolokia.jolokiaWarPreparer();
if ( preparer == null ) {
preparer = keycloakPreparer;
} else {
preparer = preparer.andThen( keycloakPreparer );
}
this.jolokia.prepareJolokiaWar(preparer);
}
}
@@ -0,0 +1,39 @@
package org.wildfly.swarm.jolokia.runtime;
import org.junit.Test;
import org.wildfly.swarm.jolokia.JolokiaFraction;
import static org.fest.assertions.Assertions.assertThat;
/**
* @author Bob McWhirter
*/
public class JolokiaKeycloakCustomizerTest {
@Test
public void testWithoutRole() {
JolokiaFraction jolokia = new JolokiaFraction();
JolokiaKeycloakCustomizer customizer = new JolokiaKeycloakCustomizer();
customizer.jolokia = jolokia;
customizer.customize();
assertThat( jolokia.jolokiaWarPreparer() ).isNull();
}
@Test
public void testWithRole() {
JolokiaFraction jolokia = new JolokiaFraction();
JolokiaKeycloakCustomizer customizer = new JolokiaKeycloakCustomizer();
customizer.jolokia = jolokia;
customizer.role = "admin";
customizer.customize();
assertThat( jolokia.jolokiaWarPreparer() ).isNotNull();
}
}
@@ -20,9 +20,13 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.Node;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.Asset;
import org.jboss.shrinkwrap.api.asset.ByteArrayAsset;
import org.jboss.shrinkwrap.api.importer.ZipImporter;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.jboss.shrinkwrap.impl.base.ArchiveBase;
import org.jboss.shrinkwrap.impl.base.AssignableBase;
import org.jboss.shrinkwrap.impl.base.importer.zip.ZipImporterImpl;
@@ -70,11 +74,11 @@ public SecuredImpl(ArchiveBase<?> archive) {
if (appArtifact != null) {
try (InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream("_bootstrap/" + appArtifact)) {
ZipImporterImpl importer = new ZipImporterImpl(archive);
importer.importFrom(in);
Node jsonNode = archive.get("keycloak.json");
Archive tmpArchive = ShrinkWrap.create(JavaArchive.class);
tmpArchive.as(ZipImporter.class).importFrom(in);
Node jsonNode = tmpArchive.get("keycloak.json");
if (jsonNode == null) {
jsonNode = archive.get("WEB-INF/keycloak.json");
jsonNode = tmpArchive.get("WEB-INF/keycloak.json");
}
if (jsonNode != null && jsonNode.getAsset() != null) {
@@ -102,6 +102,7 @@
<module>testsuite-jmx-remote-management</module>
<module>testsuite-jmx-remote-undertow</module>
<module>testsuite-jolokia</module>
<module>testsuite-jolokia-keycloak</module>
<module>testsuite-jpa</module>
<module>testsuite-jpa-mysql</module>
<module>testsuite-jpa-postgresql</module>
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2015 Red Hat, Inc. and/or its affiliates.
~
~ Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.wildfly.swarm</groupId>
<artifactId>testsuite</artifactId>
<version>2016.10-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<groupId>org.wildfly.swarm</groupId>
<artifactId>testsuite-jolokia-keycloak</artifactId>
<name>Test Suite: Jolokia with Keycloak</name>
<description>Test Suite: Jolokia with Keycloak</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>jolokia</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>keycloak</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>arquillian</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,51 @@
package org.wildfly.swarm.jolokia;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.wildfly.swarm.Swarm;
import org.wildfly.swarm.arquillian.CreateSwarm;
import org.wildfly.swarm.spi.api.JARArchive;
import static org.fest.assertions.Assertions.assertThat;
/**
* @author Bob McWhirter
*/
@RunWith(Arquillian.class)
public class JolokiaKeycloakTest {
@Deployment(testable = false)
public static Archive deployment() {
JARArchive deployment = ShrinkWrap.create(JARArchive.class);
deployment.add(EmptyAsset.INSTANCE, "nothing");
return deployment;
}
@CreateSwarm
public static Swarm createSwarm() throws Exception {
System.setProperty( JolokiaProperties.KEYCLOAK_ROLE, "admin" );
return new Swarm();
}
@Test
public void testJolokia() throws Exception {
HttpClientBuilder builder = HttpClientBuilder.create();
CloseableHttpClient client = builder.build();
HttpUriRequest request = new HttpGet("http://localhost:8080/jolokia");
CloseableHttpResponse response = client.execute(request);
assertThat( response.getStatusLine().getStatusCode() ).isEqualTo(403);
}
}

0 comments on commit ac18d97

Please sign in to comment.