Skip to content

Commit

Permalink
SWARM-123 - Provide extra configuration for Jolokia (thorntail#134)
Browse files Browse the repository at this point in the history
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 ac18d97
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 4 deletions.
27 changes: 27 additions & 0 deletions container/src/main/java/org/wildfly/swarm/DebugUtils.java
Original file line number Diff line number Diff line change
@@ -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" );
}
}
2 changes: 2 additions & 0 deletions jolokia/module.conf
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
org.wildfly.swarm.undertow
org.jboss.as.logging

*org.wildfly.swarm.keycloak
6 changes: 6 additions & 0 deletions jolokia/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ public interface JolokiaProperties {

String CONTEXT = "swarm.jolokia.context";
String ACCESS_XML = "swarm.jolokia.access.xml";
String KEYCLOAK_ROLE = "swarm.jolokia.keycloak.role";
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions testsuite/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
60 changes: 60 additions & 0 deletions testsuite/testsuite-jolokia-keycloak/pom.xml
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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.