forked from thorntail/thorntail-examples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[THORN-2039] Adding a multitenancy demo (thorntail#183)
* [THORN-2039] Adding a multitenancy demo * [THORN-2039] Improving the multitenancy demo * [THORN-2039] Adding another realm file * Updating the security pom
- Loading branch information
1 parent
5e6b95d
commit c5a2e31
Showing
12 changed files
with
492 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# Keycloak Multitenancy Example | ||
|
||
This example shows how the application and health endpoints requiring different Keycloak adapter configurations can be secured. | ||
|
||
## Start Keycloak | ||
|
||
### Keycloak Swarm Server | ||
|
||
Download the latest Swarm Keycloak standalone server jar, for example, 2018.5.0 version: | ||
|
||
``` sh | ||
wget http://repo1.maven.org/maven2/org/wildfly/swarm/servers/keycloak/2018.5.0/keycloak-2018.5.0-swarm.jar . | ||
``` | ||
and start it: | ||
|
||
``` sh | ||
THIS_EXAMPLE=/path/to/this/example | ||
java -Dswarm.http.port=8180 \ | ||
-Dkeycloak.migration.action=import \ | ||
-Dkeycloak.migration.provider=dir \ | ||
-Dkeycloak.migration.dir=${THIS_EXAMPLE}/realm \ | ||
-jar keycloak-2018.5.0-swarm.jar | ||
``` | ||
|
||
|
||
### Local installed | ||
|
||
``` sh | ||
THIS_EXAMPLE=/path/to/this/example | ||
cd $KEYCLOAK_HOME | ||
bin/standalone.sh \ | ||
-Djboss.socket.binding.port-offset=100 \ | ||
-Dkeycloak.migration.action=import \ | ||
-Dkeycloak.migration.provider=dir \ | ||
-Dkeycloak.migration.dir=${THIS_EXAMPLE}/realm | ||
``` | ||
|
||
### Docker | ||
|
||
``` sh | ||
docker run -it -d \ | ||
-p 8180:8080 \ | ||
-v `pwd`/realm:/tmp/realm \ | ||
jboss/keycloak:3.4.0.Final \ | ||
-b 0.0.0.0 \ | ||
-Dkeycloak.migration.action=import \ | ||
-Dkeycloak.migration.provider=dir \ | ||
-Dkeycloak.migration.dir=/tmp/realm | ||
``` | ||
|
||
## Build Example | ||
|
||
``` sh | ||
mvn clean package | ||
``` | ||
|
||
## Start the example server | ||
|
||
``` sh | ||
java -jar target/example-keycloak-multitenancy-swarm.jar | ||
``` | ||
|
||
### Access the secured application endpoint | ||
|
||
``` sh | ||
curl localhost:8080/app/secured -v | ||
``` | ||
|
||
You'll get the response with `401 Unauthorized`. Let's get a Token to access it. | ||
|
||
### Obtain Token from Keycloak Server | ||
|
||
``` sh | ||
USER=user1 | ||
PASS=password1 | ||
RESULT=`curl -s --data "grant_type=password&client_id=wildfly-swarm-app-client&username=${USER}&password=${PASS}" http://localhost:8180/auth/realms/wildfly-swarm-app-client/protocol/openid-connect/token` | ||
TOKEN=`echo $RESULT | sed 's/.*access_token":"//g' | sed 's/".*//g'` | ||
``` | ||
|
||
### Access the secured resource with the Token | ||
|
||
``` sh | ||
curl -H "Authorization: bearer $TOKEN" localhost:8080/app/secured | ||
``` | ||
|
||
You'll get the response which contains `Hi user1, this is Secured Resource accessed from the wildfly-swarm-app-client`. | ||
|
||
### Access the secured health endpoints | ||
|
||
``` sh | ||
curl localhost:8080/app/health -v | ||
``` | ||
|
||
You'll get the response with `401 Unauthorized`. Let's get a Token to access it. | ||
|
||
### Obtain Token from Keycloak Server | ||
|
||
``` sh | ||
USER=user1 | ||
PASS=password1 | ||
RESULT=`curl -s --data "grant_type=password&client_id=wildfly-swarm-health-client&username=${USER}&password=${PASS}" http://localhost:8180/auth/realms/wildfly-swarm-health-client/protocol/openid-connect/token` | ||
TOKEN=`echo $RESULT | sed 's/.*access_token":"//g' | sed 's/".*//g'` | ||
``` | ||
|
||
### Access the secured resource with the Token | ||
|
||
``` sh | ||
curl -H "Authorization: bearer $TOKEN" localhost:8080/app/health | ||
``` | ||
|
||
You'll get the information about the realm (wildfly-swarm-health-client) and the service health. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
~ Copyright 2017 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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" | ||
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.examples</groupId> | ||
<artifactId>examples-security</artifactId> | ||
<version>2018.6.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>example-keycloak-multitenancy</artifactId> | ||
|
||
<name>WildFly Swarm Examples: Keycloak Multitenancy</name> | ||
<description>WildFly Swarm Examples: Multitenancy</description> | ||
|
||
<packaging>war</packaging> | ||
|
||
<properties> | ||
<version.wildfly-controller-client>2.2.1.Final</version.wildfly-controller-client> | ||
</properties> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.wildfly.swarm</groupId> | ||
<artifactId>wildfly-swarm-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<id>package</id> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.wildfly.swarm</groupId> | ||
<artifactId>jaxrs</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.wildfly.swarm</groupId> | ||
<artifactId>keycloak</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.wildfly.swarm</groupId> | ||
<artifactId>microprofile-health</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.wildfly.core</groupId> | ||
<artifactId>wildfly-controller-client</artifactId> | ||
<version>${version.wildfly-controller-client}</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
43 changes: 43 additions & 0 deletions
43
security/keycloak-multitenancy/realm/wildfly-swarm-app-client-realm.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{ | ||
"id" : "wildfly-swarm-app-client", | ||
"realm" : "wildfly-swarm-app-client", | ||
"enabled" : true, | ||
"sslRequired" : "external", | ||
"roles" : { | ||
"realm" : [ { | ||
"name" : "app-admin", | ||
"description" : "Admin priviliges" | ||
} ] | ||
}, | ||
"requiredCredentials" : [ "password" ], | ||
"users" : [ { | ||
"username" : "user1", | ||
"enabled" : true, | ||
"credentials" : [ { | ||
"type" : "password", | ||
"hashedSaltedValue" : "gjPMPgJ42FC2u/erwTWG3jgBlDSgI97iv50kLvHJJBlXSQ7snHzLrUojPtjkQTdswIv4eGYt7k3mrZBewc5nIg==", | ||
"salt" : "g1OYhdfFGct8WcvSEg+FRg==", | ||
"hashIterations" : 20000, | ||
"algorithm" : "pbkdf2", | ||
"createdDate" : 1484340574721 | ||
} ], | ||
"realmRoles" : [ "app-admin" ], | ||
"clientRoles" : { | ||
"account" : [ "view-profile", "manage-account" ] | ||
} | ||
} ], | ||
"clientScopeMappings" : { | ||
"realm-management" : [ { | ||
"client" : "wildfly-swarm-app-client", | ||
"roles" : [ "app-admin" ] | ||
} ] | ||
}, | ||
"clients" : [ { | ||
"clientId" : "wildfly-swarm-app-client", | ||
"enabled" : true, | ||
"directAccessGrantsEnabled" : true, | ||
"publicClient" : true | ||
} ], | ||
|
||
"keycloakVersion" : "3.4.0.Final" | ||
} |
43 changes: 43 additions & 0 deletions
43
security/keycloak-multitenancy/realm/wildfly-swarm-health-client-realm.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{ | ||
"id" : "wildfly-swarm-health-client", | ||
"realm" : "wildfly-swarm-health-client", | ||
"enabled" : true, | ||
"sslRequired" : "external", | ||
"roles" : { | ||
"realm" : [ { | ||
"name" : "health-admin", | ||
"description" : "Admin priviliges" | ||
} ] | ||
}, | ||
"requiredCredentials" : [ "password" ], | ||
"users" : [ { | ||
"username" : "user1", | ||
"enabled" : true, | ||
"credentials" : [ { | ||
"type" : "password", | ||
"hashedSaltedValue" : "gjPMPgJ42FC2u/erwTWG3jgBlDSgI97iv50kLvHJJBlXSQ7snHzLrUojPtjkQTdswIv4eGYt7k3mrZBewc5nIg==", | ||
"salt" : "g1OYhdfFGct8WcvSEg+FRg==", | ||
"hashIterations" : 20000, | ||
"algorithm" : "pbkdf2", | ||
"createdDate" : 1484340574721 | ||
} ], | ||
"realmRoles" : [ "health-admin" ], | ||
"clientRoles" : { | ||
"account" : [ "view-profile", "manage-account" ] | ||
} | ||
} ], | ||
"clientScopeMappings" : { | ||
"realm-management" : [ { | ||
"client" : "wildfly-swarm-health-client", | ||
"roles" : [ "health-admin" ] | ||
} ] | ||
}, | ||
"clients" : [ { | ||
"clientId" : "wildfly-swarm-health-client", | ||
"enabled" : true, | ||
"directAccessGrantsEnabled" : true, | ||
"publicClient" : true | ||
} ], | ||
|
||
"keycloakVersion" : "3.4.0.Final" | ||
} |
113 changes: 113 additions & 0 deletions
113
...ycloak-multitenancy/src/main/java/org/wildfly/swarm/examples/keycloak/HealthResource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package org.wildfly.swarm.examples.keycloak; | ||
|
||
import java.io.IOException; | ||
import java.net.InetAddress; | ||
|
||
import javax.ws.rs.GET; | ||
import javax.ws.rs.Path; | ||
import javax.ws.rs.Produces; | ||
import javax.ws.rs.core.Context; | ||
import javax.ws.rs.core.HttpHeaders; | ||
|
||
import org.jboss.as.controller.client.ModelControllerClient; | ||
import org.jboss.dmr.ModelNode; | ||
import org.wildfly.swarm.SwarmInfo; | ||
|
||
@Path("health") | ||
@Produces("application/json") | ||
public class HealthResource { | ||
|
||
@Context | ||
private HttpHeaders httpHeaders; | ||
|
||
@GET | ||
public String getAll() { | ||
ModelNode node = new ModelNode(); | ||
addRealmProperty(node); | ||
node.add("node", getNodeInfo()); | ||
node.add("threads", getThreadsInfo()); | ||
node.add("heap", getHeapInfo()); | ||
|
||
return node.toJSONString(false); | ||
} | ||
|
||
@GET | ||
@Path("node") | ||
public String getNode() { | ||
return addRealmProperty(getNodeInfo()).toJSONString(false); | ||
} | ||
@GET | ||
@Path("heap") | ||
public String getHeap() { | ||
return addRealmProperty(getHeapInfo()).toJSONString(false); | ||
} | ||
@GET | ||
@Path("threads") | ||
public String getThreads() { | ||
return addRealmProperty(getThreadsInfo()).toJSONString(false); | ||
} | ||
|
||
private ModelNode getNodeInfo() { | ||
|
||
ModelNode op = new ModelNode(); | ||
op.get("address").setEmptyList(); | ||
op.get("operation").set("query"); | ||
op.get("select").add("name"); | ||
op.get("select").add("server-state"); | ||
op.get("select").add("suspend-state"); | ||
op.get("select").add("running-mode"); | ||
op.get("select").add("uuid"); | ||
|
||
return getModelNodeResponse(op); | ||
|
||
} | ||
|
||
private ModelNode getHeapInfo() { | ||
ModelNode op = new ModelNode(); | ||
op.get("address").add("core-service", "platform-mbean"); | ||
op.get("address").add("type", "memory"); | ||
op.get("operation").set("query"); | ||
op.get("select").add("heap-memory-usage"); | ||
op.get("select").add("non-heap-memory-usage"); | ||
|
||
return getModelNodeResponse(op); | ||
} | ||
|
||
private ModelNode getThreadsInfo() { | ||
ModelNode op = new ModelNode(); | ||
op.get("address").add("core-service", "platform-mbean"); | ||
op.get("address").add("type", "threading"); | ||
op.get("operation").set("query"); | ||
op.get("select").add("thread-count"); | ||
op.get("select").add("peak-thread-count"); | ||
op.get("select").add("total-started-thread-count"); | ||
op.get("select").add("current-thread-cpu-time"); | ||
op.get("select").add("current-thread-user-time"); | ||
|
||
return getModelNodeResponse(op); | ||
} | ||
|
||
private static ModelNode unwrap(ModelNode response) { | ||
if (response.get("outcome").asString().equals("success")) { | ||
return response.get("result"); | ||
} else { | ||
return response; | ||
} | ||
} | ||
|
||
private ModelNode addRealmProperty(ModelNode node) { | ||
return node.add("realm", httpHeaders.getHeaderString("Realm")); | ||
} | ||
|
||
private ModelNode getModelNodeResponse(ModelNode op) { | ||
try (ModelControllerClient client = ModelControllerClient.Factory.create( | ||
InetAddress.getByName("localhost"), 9990)) { | ||
ModelNode response = client.execute(op); | ||
ModelNode unwrapped = unwrap(response); | ||
unwrapped.get("swarm-version").set(SwarmInfo.VERSION); | ||
return unwrapped; | ||
} catch (IOException e) { | ||
return new ModelNode().get("failure-description").set(e.getMessage()); | ||
} | ||
} | ||
} |
Oops, something went wrong.