Merge pull request #142 from patriot1burke/master

undertow/wildfly adapter
This commit is contained in:
Bill Burke 2013-12-18 15:11:32 -08:00
commit e17c7c2c1b
44 changed files with 337 additions and 290 deletions

View file

@ -34,18 +34,4 @@ public class SkeletonKeySession implements Serializable {
return metadata; return metadata;
} }
protected static ThreadLocal<SkeletonKeySession> local = new ThreadLocal<SkeletonKeySession>();
public static void pushContext(SkeletonKeySession session) {
local.set(session);
}
public static void clearContext() {
local.set(null);
}
public static SkeletonKeySession getContext() {
return local.get();
}
} }

View file

@ -8,7 +8,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
/** /**
* Any class that extends JsonWebToken will use NON_DEFAULT inclusion * Utility class to handle simple JSON serializable for Keycloak.
* *
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $

View file

@ -22,8 +22,8 @@ public class CustomerDatabaseClient {
static class TypedList extends ArrayList<String> {} static class TypedList extends ArrayList<String> {}
public static List<String> getCustomers() { public static List<String> getCustomers(HttpServletRequest req) {
SkeletonKeySession session = SkeletonKeySession.getContext(); SkeletonKeySession session = (SkeletonKeySession)req.getAttribute(SkeletonKeySession.class.getName());
HttpClient client = new HttpClientBuilder() HttpClient client = new HttpClientBuilder()
.trustStore(session.getMetadata().getTruststore()) .trustStore(session.getMetadata().getTruststore())
.hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY).build(); .hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY).build();

View file

@ -16,7 +16,7 @@
User <b><%=request.getUserPrincipal().getName()%></b> made this request. User <b><%=request.getUserPrincipal().getName()%></b> made this request.
<h2>Customer Listing</h2> <h2>Customer Listing</h2>
<% <%
java.util.List<String> list = CustomerDatabaseClient.getCustomers(); java.util.List<String> list = CustomerDatabaseClient.getCustomers(request);
for (String cust : list) for (String cust : list)
{ {
out.print("<p>"); out.print("<p>");

View file

@ -8,6 +8,7 @@ import org.keycloak.SkeletonKeySession;
import org.keycloak.adapters.HttpClientBuilder; import org.keycloak.adapters.HttpClientBuilder;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
@ -21,8 +22,8 @@ public class ProductDatabaseClient
{ {
static class TypedList extends ArrayList<String> {} static class TypedList extends ArrayList<String> {}
public static List<String> getProducts() { public static List<String> getProducts(HttpServletRequest req) {
SkeletonKeySession session = SkeletonKeySession.getContext(); SkeletonKeySession session = (SkeletonKeySession)req.getAttribute(SkeletonKeySession.class.getName());
HttpClient client = new HttpClientBuilder() HttpClient client = new HttpClientBuilder()
.trustStore(session.getMetadata().getTruststore()) .trustStore(session.getMetadata().getTruststore())
.hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY).build(); .hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY).build();

View file

@ -17,7 +17,7 @@
User <b><%=request.getUserPrincipal().getName()%></b> made this request. User <b><%=request.getUserPrincipal().getName()%></b> made this request.
<h2>Product Listing</h2> <h2>Product Listing</h2>
<% <%
java.util.List<String> list = ProductDatabaseClient.getProducts(); java.util.List<String> list = ProductDatabaseClient.getProducts(request);
for (String cust : list) for (String cust : list)
{ {
out.print("<p>"); out.print("<p>");

View file

@ -35,5 +35,6 @@
</build> </build>
<modules> <modules>
<module>as7-eap-demo</module> <module>as7-eap-demo</module>
<module>wildfly-demo</module>
</modules> </modules>
</project> </project>

View file

@ -11,7 +11,7 @@
<groupId>org.keycloak.example.wildfly.demo</groupId> <groupId>org.keycloak.example.wildfly.demo</groupId>
<artifactId>customer-portal-example</artifactId> <artifactId>customer-portal-example</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
<name>Customer Portal - Secured via Undertow</name> <name>Customer Portal - Secured via Valve</name>
<description/> <description/>
<repositories> <repositories>
@ -28,21 +28,6 @@
<artifactId>jboss-servlet-api_3.0_spec</artifactId> <artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-undertow-adapter</artifactId> <artifactId>keycloak-undertow-adapter</artifactId>

View file

@ -1,36 +0,0 @@
package org.jboss.resteasy.example.oauth;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.SkeletonKeySession;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CustomerDatabaseClient
{
public static List<String> getCustomers(HttpServletRequest request)
{
SkeletonKeySession session = (SkeletonKeySession)request.getAttribute(SkeletonKeySession.class.getName());
ResteasyClient client = new ResteasyClientBuilder()
.trustStore(session.getMetadata().getTruststore())
.hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY).build();
try
{
Response response = client.target("http://localhost:8080/database/customers").request()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + session.getTokenString()).get();
return response.readEntity(new GenericType<List<String>>(){});
}
finally
{
client.close();
}
}
}

View file

@ -0,0 +1,50 @@
package org.keycloak.example;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.keycloak.SkeletonKeySession;
import org.keycloak.adapters.HttpClientBuilder;
import org.keycloak.util.JsonSerialization;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CustomerDatabaseClient {
static class TypedList extends ArrayList<String> {}
public static List<String> getCustomers(HttpServletRequest req) {
SkeletonKeySession session = (SkeletonKeySession)req.getAttribute(SkeletonKeySession.class.getName());
HttpClient client = new HttpClientBuilder()
.trustStore(session.getMetadata().getTruststore())
.hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY).build();
try {
HttpGet get = new HttpGet("http://localhost:8080/database/customers");
get.addHeader("Authorization", "Bearer " + session.getTokenString());
try {
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
try {
return JsonSerialization.readValue(is, TypedList.class);
} finally {
is.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
} finally {
client.getConnectionManager().shutdown();
}
}
}

View file

@ -2,10 +2,6 @@
<deployment> <deployment>
<!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute --> <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
<dependencies> <dependencies>
<module name="org.bouncycastle"/>
<module name="org.jboss.resteasy.resteasy-jaxrs" services="import"/>
<module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
<module name="org.jboss.resteasy.jose-jwt" />
</dependencies> </dependencies>
</deployment> </deployment>
</jboss-deployment-structure> </jboss-deployment-structure>

View file

@ -1,5 +0,0 @@
<jboss-web>
<valve>
<class-name>org.keycloak.adapters.as7.OAuthManagedResourceValve</class-name>
</valve>
</jboss-web>

View file

@ -2,7 +2,7 @@
pageEncoding="ISO-8859-1"%> pageEncoding="ISO-8859-1"%>
<html> <html>
<head> <head>
<title>Customer Admin Iterface</title> <title>Customer Admin Interface</title>
</head> </head>
<body bgcolor="#E3F6CE"> <body bgcolor="#E3F6CE">
<h1>Customer Admin Interface</h1> <h1>Customer Admin Interface</h1>

View file

@ -1,20 +1,22 @@
<%@ page import="javax.ws.rs.core.UriBuilder" language="java" contentType="text/html; charset=ISO-8859-1" <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%> pageEncoding="ISO-8859-1"%>
<%@ page import="org.keycloak.example.CustomerDatabaseClient" %>
<%@ page import="org.keycloak.util.KeycloakUriBuilder" %>
<html> <html>
<head> <head>
<title>Customer View Page</title> <title>Customer View Page</title>
</head> </head>
<body bgcolor="#E3F6CE"> <body bgcolor="#E3F6CE">
<% <%
String logoutUri = KeycloakUriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
String logoutUri = UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout") .queryParam("redirect_uri", "http://localhost:8080/customer-portal").build().toString();
.queryParam("redirect_uri", "http://localhost:8080/customer-portal").build().toString(); String acctUri = "http://localhost:8080/auth-server/rest/realms/demo/account";
%> %>
<p>Goto: <a href="http://localhost:8080/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a></p> <p>Goto: <a href="http://localhost:8080/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a> | <a href="<%=acctUri%>">manage acct</a></p>
User <b><%=request.getUserPrincipal().getName()%></b> made this request. User <b><%=request.getUserPrincipal().getName()%></b> made this request.
<h2>Customer Listing</h2> <h2>Customer Listing</h2>
<% <%
java.util.List<String> list = org.jboss.resteasy.example.oauth.CustomerDatabaseClient.getCustomers(request); java.util.List<String> list = CustomerDatabaseClient.getCustomers(request);
for (String cust : list) for (String cust : list)
{ {
out.print("<p>"); out.print("<p>");

View file

@ -30,29 +30,40 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>keycloak-core</artifactId> <artifactId>resteasy-jaxrs</artifactId>
<version>${project.version}</version> <scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-undertow-adapter</artifactId> <artifactId>keycloak-undertow-adapter</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<!--
<exclusions>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
-->
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<finalName>database</finalName> <finalName>database</finalName>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.jboss.as.plugins</groupId> <groupId>org.jboss.as.plugins</groupId>
<artifactId>jboss-as-maven-plugin</artifactId> <artifactId>jboss-as-maven-plugin</artifactId>
<version>7.5.Final</version> <version>7.4.Final</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View file

@ -2,8 +2,6 @@
<deployment> <deployment>
<!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute --> <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
<dependencies> <dependencies>
<module name="org.bouncycastle"/>
<module name="org.jboss.resteasy.jose-jwt" />
</dependencies> </dependencies>
</deployment> </deployment>
</jboss-deployment-structure> </jboss-deployment-structure>

View file

@ -1,5 +0,0 @@
<jboss-web>
<valve>
<class-name>org.keycloak.adapters.as7.BearerTokenAuthenticatorValve</class-name>
</valve>
</jboss-web>

View file

@ -2,7 +2,7 @@
"realm" : "demo", "realm" : "demo",
"resource" : "database-service", "resource" : "database-service",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"enable-cors" : true, "bearer-only" : true,
"bearer-only" : true "enable-cors" : true
} }

View file

@ -26,7 +26,7 @@
<plugin> <plugin>
<groupId>org.jboss.as.plugins</groupId> <groupId>org.jboss.as.plugins</groupId>
<artifactId>jboss-as-maven-plugin</artifactId> <artifactId>jboss-as-maven-plugin</artifactId>
<version>7.5.Final</version> <version>7.1.1.Final</version>
<configuration> <configuration>
<skip>true</skip> <skip>true</skip>
</configuration> </configuration>

View file

@ -11,7 +11,7 @@
<groupId>org.keycloak.example.wildfly.demo</groupId> <groupId>org.keycloak.example.wildfly.demo</groupId>
<artifactId>product-portal-example</artifactId> <artifactId>product-portal-example</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
<name>Product Portal - Secured via Undertow</name> <name>Product Portal </name>
<description/> <description/>
<repositories> <repositories>
@ -28,21 +28,6 @@
<artifactId>jboss-servlet-api_3.0_spec</artifactId> <artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-undertow-adapter</artifactId> <artifactId>keycloak-undertow-adapter</artifactId>
@ -56,7 +41,7 @@
<plugin> <plugin>
<groupId>org.jboss.as.plugins</groupId> <groupId>org.jboss.as.plugins</groupId>
<artifactId>jboss-as-maven-plugin</artifactId> <artifactId>jboss-as-maven-plugin</artifactId>
<version>7.5.Final</version> <version>7.4.Final</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View file

@ -1,36 +0,0 @@
package org.jboss.resteasy.example.oauth;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.SkeletonKeySession;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ProductDatabaseClient
{
public static List<String> getProducts(HttpServletRequest request)
{
SkeletonKeySession session = (SkeletonKeySession)request.getAttribute(SkeletonKeySession.class.getName());
ResteasyClient client = new ResteasyClientBuilder()
.trustStore(session.getMetadata().getTruststore())
.hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY).build();
try
{
Response response = client.target("http://localhost:8080/database/products").request()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + session.getTokenString()).get();
return response.readEntity(new GenericType<List<String>>(){});
}
finally
{
client.close();
}
}
}

View file

@ -0,0 +1,50 @@
package org.keycloak.example.oauth;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.keycloak.SkeletonKeySession;
import org.keycloak.adapters.HttpClientBuilder;
import org.keycloak.util.JsonSerialization;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ProductDatabaseClient
{
static class TypedList extends ArrayList<String> {}
public static List<String> getProducts(HttpServletRequest req) {
SkeletonKeySession session = (SkeletonKeySession)req.getAttribute(SkeletonKeySession.class.getName());
HttpClient client = new HttpClientBuilder()
.trustStore(session.getMetadata().getTruststore())
.hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY).build();
try {
HttpGet get = new HttpGet("http://localhost:8080/database/products");
get.addHeader("Authorization", "Bearer " + session.getTokenString());
try {
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
try {
return JsonSerialization.readValue(is, TypedList.class);
} finally {
is.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
} finally {
client.getConnectionManager().shutdown();
}
}
}

View file

@ -2,10 +2,6 @@
<deployment> <deployment>
<!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute --> <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
<dependencies> <dependencies>
<module name="org.bouncycastle"/>
<module name="org.jboss.resteasy.resteasy-jaxrs" services="import"/>
<module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
<module name="org.jboss.resteasy.jose-jwt" />
</dependencies> </dependencies>
</deployment> </deployment>
</jboss-deployment-structure> </jboss-deployment-structure>

View file

@ -1,5 +0,0 @@
<jboss-web>
<valve>
<class-name>org.keycloak.adapters.as7.OAuthManagedResourceValve</class-name>
</valve>
</jboss-web>

View file

@ -1,20 +1,23 @@
<%@ page import="javax.ws.rs.core.UriBuilder" language="java" contentType="text/html; charset=ISO-8859-1" <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%> pageEncoding="ISO-8859-1"%>
<%@ page import="org.keycloak.example.oauth.ProductDatabaseClient" %>
<%@ page import="org.keycloak.util.KeycloakUriBuilder" %>
<html> <html>
<head> <head>
<title>Product View Page</title> <title>Product View Page</title>
</head> </head>
<body bgcolor="#F5F6CE"> <body bgcolor="#F5F6CE">
<% <%
String logoutUri = UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout") String logoutUri = KeycloakUriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
.queryParam("redirect_uri", "http://localhost:8080/product-portal").build().toString(); .queryParam("redirect_uri", "http://localhost:8080/product-portal").build().toString();
String acctUri = "http://localhost:8080/auth-server/rest/realms/demo/account";
%> %>
<p>Goto: <a href="http://localhost:8080/customer-portal">customers</a> | <a href="<%=logoutUri%>">logout</a></p> <p>Goto: <a href="http://localhost:8080/customer-portal">customers</a> | <a href="<%=logoutUri%>">logout</a> | <a href="<%=acctUri%>">manage acct</a></p>
User <b><%=request.getUserPrincipal().getName()%></b> made this request. User <b><%=request.getUserPrincipal().getName()%></b> made this request.
<h2>Product Listing</h2> <h2>Product Listing</h2>
<% <%
java.util.List<String> list = org.jboss.resteasy.example.oauth.ProductDatabaseClient.getProducts(request); java.util.List<String> list = ProductDatabaseClient.getProducts(request);
for (String cust : list) for (String cust : list)
{ {
out.print("<p>"); out.print("<p>");

View file

@ -15,11 +15,20 @@
<description/> <description/>
<dependencies> <dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId> <artifactId>keycloak-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core-jaxrs</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-services</artifactId> <artifactId>keycloak-services</artifactId>
@ -30,6 +39,11 @@
<artifactId>keycloak-model-api</artifactId> <artifactId>keycloak-model-api</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-jpa</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-social-core</artifactId> <artifactId>keycloak-social-core</artifactId>
@ -65,6 +79,7 @@
<artifactId>keycloak-admin-ui-styles</artifactId> <artifactId>keycloak-admin-ui-styles</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<!--
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId> <artifactId>resteasy-jaxrs</artifactId>
@ -89,6 +104,7 @@
<artifactId>jaxrs-api</artifactId> <artifactId>jaxrs-api</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
-->
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>
@ -101,16 +117,48 @@
<groupId>de.flapdoodle.embed</groupId> <groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId> <artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.1</version> <version>4.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<!-- resteasy -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>async-http-servlet-3.0</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>jaxrs-api</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -119,7 +167,7 @@
<plugin> <plugin>
<groupId>org.jboss.as.plugins</groupId> <groupId>org.jboss.as.plugins</groupId>
<artifactId>jboss-as-maven-plugin</artifactId> <artifactId>jboss-as-maven-plugin</artifactId>
<version>7.5.Final</version> <version>7.4.Final</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View file

@ -1,6 +1,6 @@
package org.keycloak.example.demo; package org.keycloak.example.demo;
import org.jboss.resteasy.jwt.JsonSerialization; import org.keycloak.util.JsonSerialization;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
@ -10,7 +10,6 @@ import org.keycloak.services.resources.KeycloakApplication;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
/** /**
@ -39,17 +38,8 @@ public class DemoApplication extends KeycloakApplication {
public static RealmRepresentation loadJson(String path) public static RealmRepresentation loadJson(String path)
{ {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path); InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
ByteArrayOutputStream os = new ByteArrayOutputStream();
int c;
try { try {
while ( (c = is.read()) != -1) return JsonSerialization.readValue(is, RealmRepresentation.class);
{
os.write(c);
}
byte[] bytes = os.toByteArray();
//System.out.println(new String(bytes));
return JsonSerialization.fromBytes(RealmRepresentation.class, bytes);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View file

@ -1,20 +1,20 @@
{ {
"realm": "demo", "realm": "demo",
"enabled": true, "enabled": true,
"tokenLifespan": 300, "tokenLifespan": 3000,
"accessCodeLifespan": 10, "accessCodeLifespan": 10,
"accessCodeLifespanUserAction": 600, "accessCodeLifespanUserAction": 6000,
"accountManagement": true,
"sslNotRequired": true, "sslNotRequired": true,
"cookieLoginAllowed": true, "cookieLoginAllowed": true,
"registrationAllowed": true, "registrationAllowed": false,
"social": true, "social": false,
"automaticRegistrationAfterSocialLogin": false, "automaticRegistrationAfterSocialLogin": false,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"requiredCredentials": [ "password" ], "requiredCredentials": [ "password" ],
"requiredApplicationCredentials": [ "password" ], "requiredApplicationCredentials": [ "password" ],
"requiredOAuthClientCredentials": [ "password" ], "requiredOAuthClientCredentials": [ "password" ],
"defaultRoles": [ "user" ],
"users" : [ "users" : [
{ {
"username" : "bburke@redhat.com", "username" : "bburke@redhat.com",
@ -26,48 +26,44 @@
{ "type" : "password", { "type" : "password",
"value" : "password" } "value" : "password" }
] ]
},
{
"username" : "third-party",
"enabled": true,
"credentials" : [
{ "type" : "password",
"value" : "password" }
]
} }
], ],
"roles": [ "roles": [
{ {
"name": "user", "name": "user",
"description": "Have User privileges" "description": "User privileges"
}, },
{ {
"name": "admin", "name": "admin",
"description": "Have Administrator privileges" "description": "Administrator privileges"
} }
], ],
"roleMappings": [ "roleMappings": [
{ {
"username": "bburke@redhat.com", "username": "bburke@redhat.com",
"roles": ["user"] "roles": ["user"]
},
{
"username": "third-party",
"roles": ["KEYCLOAK_IDENTITY_REQUESTER"]
} }
], ],
"scopeMappings": [ "scopeMappings": [
{ {
"username": "third-party", "username": "third-party",
"roles": ["user"] "roles": ["user"]
},
{
"username": "customer-portal",
"roles": ["user"]
},
{
"username": "product-portal",
"roles": ["user"]
} }
], ],
"applications": [ "applications": [
{ {
"name": "customer-portal", "name": "customer-portal",
"enabled": true, "enabled": true,
"adminUrl": "http://localhost:8080/customer-portal/j_admin_request", "adminUrl": "http://localhost:8080/customer-portal/j_admin_request",
"useRealmMappings": true,
"credentials": [ "credentials": [
{ {
"type": "password", "type": "password",
@ -79,7 +75,6 @@
"name": "product-portal", "name": "product-portal",
"enabled": true, "enabled": true,
"adminUrl": "http://localhost:8080/product-portal/j_admin_request", "adminUrl": "http://localhost:8080/product-portal/j_admin_request",
"useRealmMappings": true,
"credentials": [ "credentials": [
{ {
"type": "password", "type": "password",
@ -87,5 +82,26 @@
} }
] ]
} }
] ],
} "oauthClients": [
{
"name": "third-party",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password"
}
]
}
],
"applicationRoleMappings": {
"Account": [
{
"username": "bburke@redhat.com",
"roles": ["manage-account"]
}
]
}
}

View file

@ -1,10 +1,21 @@
<jboss-deployment-structure> <jboss-deployment-structure>
<deployment> <deployment>
<!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute --> <exclusions>
<dependencies>
<module name="org.jboss.resteasy.jose-jwt"/> <!-- Exclude Version cxf of JBOSS -->
<module name="org.jboss.resteasy.resteasy-crypto"/> <module name="org.apache.cxf" />
<module name="org.bouncycastle"/> <!-- Exclude JAVA EE of JBOSS (javax.ws..) => Add dependency javax.annotation -->
</dependencies> <module name="javaee.api" />
</deployment> <!-- Exclude RestEasy conflict (javax.ws.rs.ext.RunDelegate) -->
<module name="org.jboss.resteasy.resteasy-atom-provider" />
<module name="org.jboss.resteasy.resteasy-cdi" />
<module name="org.jboss.resteasy.resteasy-jackson-provider" />
<module name="org.jboss.resteasy.resteasy-jaxb-provider" />
<module name="org.jboss.resteasy.resteasy-jaxrs" />
<module name="org.jboss.resteasy.resteasy-jettison-provider" />
<module name="org.jboss.resteasy.resteasy-jsapi" />
<module name="org.jboss.resteasy.resteasy-multipart-provider" />
<module name="org.jboss.resteasy.resteasy-yaml-provider" />
</exclusions>
</deployment>
</jboss-deployment-structure> </jboss-deployment-structure>

View file

@ -11,7 +11,7 @@
<groupId>org.keycloak.example.wildfly.demo</groupId> <groupId>org.keycloak.example.wildfly.demo</groupId>
<artifactId>oauth-client-example</artifactId> <artifactId>oauth-client-example</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
<name>Simple OAuth Wildfly Client</name> <name>Simple OAuth Client</name>
<description/> <description/>
<dependencies> <dependencies>
@ -21,19 +21,9 @@
<version>1.0.1.Final</version> <version>1.0.1.Final</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId> <artifactId>keycloak-servlet-oauth-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -44,7 +34,7 @@
<plugin> <plugin>
<groupId>org.jboss.as.plugins</groupId> <groupId>org.jboss.as.plugins</groupId>
<artifactId>jboss-as-maven-plugin</artifactId> <artifactId>jboss-as-maven-plugin</artifactId>
<version>7.5.Final</version> <version>7.4.Final</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View file

@ -1,6 +1,5 @@
package org.jboss.resteasy.example.oauth; package org.keycloak.example.oauth;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.servlet.ServletOAuthClient; import org.keycloak.servlet.ServletOAuthClient;
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextEvent;
@ -55,7 +54,6 @@ public class Bootstrap implements ServletContextListener {
client.setPassword("password"); client.setPassword("password");
client.setAuthUrl("http://localhost:8080/auth-server/rest/realms/demo/tokens/login"); client.setAuthUrl("http://localhost:8080/auth-server/rest/realms/demo/tokens/login");
client.setCodeUrl("http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes"); client.setCodeUrl("http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes");
client.setClient(new ResteasyClientBuilder().build());
client.start(); client.start();
sce.getServletContext().setAttribute(ServletOAuthClient.class.getName(), client); sce.getServletContext().setAttribute(ServletOAuthClient.class.getName(), client);

View file

@ -1,15 +1,18 @@
package org.jboss.resteasy.example.oauth; package org.keycloak.example.oauth;
import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.apache.http.HttpEntity;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.keycloak.adapters.TokenGrantRequest;
import org.keycloak.servlet.ServletOAuthClient; import org.keycloak.servlet.ServletOAuthClient;
import org.keycloak.util.JsonSerialization;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@ -31,6 +34,8 @@ public class ProductDatabaseClient {
} }
} }
static class TypedList extends ArrayList<String> {}
public static List<String> getProducts(HttpServletRequest request) { public static List<String> getProducts(HttpServletRequest request) {
// This is really the worst code ever. The ServletOAuthClient is obtained by getting a context attribute // This is really the worst code ever. The ServletOAuthClient is obtained by getting a context attribute
// that is set in the Bootstrap context listenr in this project. // that is set in the Bootstrap context listenr in this project.
@ -38,32 +43,30 @@ public class ProductDatabaseClient {
// and obtain the ServletOAuthClient. I actually suggest downloading the ServletOAuthClient code // and obtain the ServletOAuthClient. I actually suggest downloading the ServletOAuthClient code
// and take a look how it works. // and take a look how it works.
ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName()); ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
String token = oAuthClient.getBearerToken(request); String token = null;
ResteasyClient client = new ResteasyClientBuilder()
.trustStore(oAuthClient.getTruststore())
.hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY).build();
try { try {
// invoke without the Authorization header token = oAuthClient.getBearerToken(request);
Response response = client.target("http://localhost:8080/database/products").request().get(); } catch (IOException e) {
response.close(); throw new RuntimeException(e);
if (response.getStatus() != 401) { } catch (TokenGrantRequest.HttpFailure failure) {
response.close(); throw new RuntimeException(failure);
client.close();
throw new RuntimeException("Expecting an auth status code: " + response.getStatus());
}
} finally {
} }
HttpClient client = oAuthClient.getClient();
HttpGet get = new HttpGet("http://localhost:8080/database/products");
get.addHeader("Authorization", "Bearer " + token);
try { try {
Response response = client.target("http://localhost:8080/database/products").request() HttpResponse response = client.execute(get);
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token).get(); HttpEntity entity = response.getEntity();
if (response.getStatus() != 200) { InputStream is = entity.getContent();
response.close(); try {
throw new RuntimeException("Failed to access!: " + response.getStatus()); return JsonSerialization.readValue(is, TypedList.class);
} finally {
is.close();
} }
return response.readEntity(new GenericType<List<String>>() { } catch (IOException e) {
}); throw new RuntimeException(e);
} finally {
client.close();
} }
} }
} }

View file

@ -2,8 +2,6 @@
<deployment> <deployment>
<!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute --> <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
<dependencies> <dependencies>
<module name="org.jboss.resteasy.resteasy-jaxrs" services="import"/>
<module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
</dependencies> </dependencies>
</deployment> </deployment>
</jboss-deployment-structure> </jboss-deployment-structure>

View file

@ -7,7 +7,7 @@
<module-name>oauth-client</module-name> <module-name>oauth-client</module-name>
<listener> <listener>
<listener-class>org.jboss.resteasy.example.oauth.Bootstrap</listener-class> <listener-class>org.keycloak.example.oauth.Bootstrap</listener-class>
</listener> </listener>
<!-- <!--
<security-constraint> <security-constraint>

3
examples/wildfly-demo/third-party/src/main/webapp/pull_data.jsp vendored Normal file → Executable file
View file

@ -1,3 +1,4 @@
<%@ page import="org.keycloak.example.oauth.ProductDatabaseClient" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%> pageEncoding="ISO-8859-1"%>
<html> <html>
@ -7,7 +8,7 @@
<body> <body>
<h2>Pulled Product Listing</h2> <h2>Pulled Product Listing</h2>
<% <%
java.util.List<String> list = org.jboss.resteasy.example.oauth.ProductDatabaseClient.getProducts(request); java.util.List<String> list = ProductDatabaseClient.getProducts(request);
for (String prod : list) for (String prod : list)
{ {
out.print("<p>"); out.print("<p>");

4
examples/wildfly-demo/third-party/src/main/webapp/redirect.jsp vendored Normal file → Executable file
View file

@ -1,3 +1,3 @@
<% <%@ page import="org.keycloak.example.oauth.ProductDatabaseClient" %><%
org.jboss.resteasy.example.oauth.ProductDatabaseClient.redirect(request, response); ProductDatabaseClient.redirect(request, response);
%> %>

View file

@ -63,7 +63,6 @@ public class BearerTokenAuthenticatorValve extends AuthenticatorBase implements
} }
super.invoke(request, response); super.invoke(request, response);
} finally { } finally {
SkeletonKeySession.clearContext();
} }
} }

View file

@ -108,7 +108,6 @@ public class CatalinaBearerTokenAuthenticator {
request.setAuthType("OAUTH_BEARER"); request.setAuthType("OAUTH_BEARER");
SkeletonKeySession skSession = new SkeletonKeySession(tokenString, token, resourceMetadata); SkeletonKeySession skSession = new SkeletonKeySession(tokenString, token, resourceMetadata);
request.setAttribute(SkeletonKeySession.class.getName(), skSession); request.setAttribute(SkeletonKeySession.class.getName(), skSession);
SkeletonKeySession.pushContext(skSession);
return true; return true;
} }

View file

@ -86,7 +86,6 @@ public class OAuthAuthenticatorValve extends FormAuthenticator implements Lifecy
} }
super.invoke(request, response); super.invoke(request, response);
} finally { } finally {
SkeletonKeySession.clearContext();
} }
} }
@ -199,8 +198,6 @@ public class OAuthAuthenticatorValve extends FormAuthenticator implements Lifecy
SkeletonKeySession skSession = (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName()); SkeletonKeySession skSession = (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName());
if (skSession != null) { if (skSession != null) {
request.setAttribute(SkeletonKeySession.class.getName(), skSession); request.setAttribute(SkeletonKeySession.class.getName(), skSession);
SkeletonKeySession.pushContext(skSession);
} }
} }
return true; return true;

View file

@ -104,7 +104,7 @@ public class BearerTokenAuthenticator {
X509Certificate[] chain = new X509Certificate[0]; X509Certificate[] chain = new X509Certificate[0];
try { try {
chain = exchange.getConnection().getSslSessionInfo().getPeerCertificateChain(); chain = exchange.getConnection().getSslSessionInfo().getPeerCertificateChain();
} catch (SSLPeerUnverifiedException ignore) { } catch (Exception ignore) {
} }
if (chain == null || chain.length == 0) { if (chain == null || chain.length == 0) {

View file

@ -115,7 +115,7 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism
return accountRoles; return accountRoles;
} }
}; };
securityContext.authenticationComplete(account, "FORM"); securityContext.authenticationComplete(account, "KEYCLOAK", true);
} }
protected void propagateBearer(HttpServerExchange exchange, SkeletonKeySession session) { protected void propagateBearer(HttpServerExchange exchange, SkeletonKeySession session) {

View file

@ -1,10 +1,15 @@
package org.keycloak.adapters.undertow; package org.keycloak.adapters.undertow;
import io.undertow.security.api.AuthenticationMechanism;
import io.undertow.security.api.AuthenticationMechanismFactory;
import io.undertow.security.idm.Account; import io.undertow.security.idm.Account;
import io.undertow.security.idm.Credential; import io.undertow.security.idm.Credential;
import io.undertow.security.idm.IdentityManager; import io.undertow.security.idm.IdentityManager;
import io.undertow.server.handlers.form.FormParserFactory;
import io.undertow.servlet.ServletExtension; import io.undertow.servlet.ServletExtension;
import io.undertow.servlet.api.AuthMethodConfig;
import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.LoginConfig;
import io.undertow.servlet.api.ServletSessionConfig; import io.undertow.servlet.api.ServletSessionConfig;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.representations.config.AdapterConfig; import org.keycloak.representations.config.AdapterConfig;
@ -12,6 +17,7 @@ import org.keycloak.adapters.config.RealmConfigurationLoader;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import java.io.InputStream; import java.io.InputStream;
import java.util.Map;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -20,21 +26,34 @@ import java.io.InputStream;
public class KeycloakServletExtension implements ServletExtension { public class KeycloakServletExtension implements ServletExtension {
protected Logger log = Logger.getLogger(KeycloakServletExtension.class); protected Logger log = Logger.getLogger(KeycloakServletExtension.class);
// todo when this DeploymentInfo method of the same name is fixed.
public boolean isAuthenticationMechanismPresent(DeploymentInfo deploymentInfo, final String mechanismName) {
LoginConfig loginConfig = deploymentInfo.getLoginConfig();
if(loginConfig != null) {
for(AuthMethodConfig method : loginConfig.getAuthMethods()) {
if(method.getName().equalsIgnoreCase(mechanismName)) {
return true;
}
}
}
return false;
}
@Override @Override
public void handleDeployment(DeploymentInfo deploymentInfo, ServletContext servletContext) { public void handleDeployment(DeploymentInfo deploymentInfo, ServletContext servletContext) {
if (deploymentInfo.getLoginConfig() == null || !deploymentInfo.getLoginConfig().getAuthMethod().equalsIgnoreCase("keycloak")) { if (!isAuthenticationMechanismPresent(deploymentInfo, "KEYCLOAK")) {
log.info("auth-method is not keycloak!"); log.info("auth-method is not keycloak!");
return; return;
} }
log.info("KeycloakServletException initialization"); log.info("KeycloakServletException initialization");
deploymentInfo.setIgnoreStandardAuthenticationMechanism(true);
InputStream is = servletContext.getResourceAsStream("/WEB-INF/keycloak.json"); InputStream is = servletContext.getResourceAsStream("/WEB-INF/keycloak.json");
if (is == null) throw new RuntimeException("Unable to find /WEB-INF/keycloak.json configuration file"); if (is == null) throw new RuntimeException("Unable to find /WEB-INF/keycloak.json configuration file");
RealmConfigurationLoader loader = new RealmConfigurationLoader(is); RealmConfigurationLoader loader = new RealmConfigurationLoader(is);
loader.init(true); loader.init(true);
AdapterConfig keycloakConfig = loader.getAdapterConfig(); AdapterConfig keycloakConfig = loader.getAdapterConfig();
PreflightCorsHandler.Wrapper preflight = new PreflightCorsHandler.Wrapper(keycloakConfig); PreflightCorsHandler.Wrapper preflight = new PreflightCorsHandler.Wrapper(keycloakConfig);
ServletKeycloakAuthenticationMechanism auth = new ServletKeycloakAuthenticationMechanism(loader.getResourceMetadata(), final ServletKeycloakAuthenticationMechanism auth = new ServletKeycloakAuthenticationMechanism(loader.getResourceMetadata(),
keycloakConfig, keycloakConfig,
loader.getRealmConfiguration(), loader.getRealmConfiguration(),
deploymentInfo.getConfidentialPortManager()); deploymentInfo.getConfidentialPortManager());
@ -43,7 +62,12 @@ public class KeycloakServletExtension implements ServletExtension {
// setup handlers // setup handlers
deploymentInfo.addInitialHandlerChainWrapper(preflight); // cors preflight deploymentInfo.addInitialHandlerChainWrapper(preflight); // cors preflight
deploymentInfo.addAuthenticationMechanism(auth); // authentication deploymentInfo.addAuthenticationMechanism("KEYCLOAK", new AuthenticationMechanismFactory() {
@Override
public AuthenticationMechanism create(String s, FormParserFactory formParserFactory, Map<String, String> stringStringMap) {
return auth;
}
}); // authentication
deploymentInfo.addInnerHandlerChainWrapper(ServletPropagateSessionHandler.WRAPPER); // propagates SkeletonKeySession deploymentInfo.addInnerHandlerChainWrapper(ServletPropagateSessionHandler.WRAPPER); // propagates SkeletonKeySession
deploymentInfo.addInnerHandlerChainWrapper(actions); // handles authenticated actions and cors. deploymentInfo.addInnerHandlerChainWrapper(actions); // handles authenticated actions and cors.

View file

@ -32,7 +32,6 @@ public class OAuthAuthenticator {
protected String tokenString; protected String tokenString;
protected SkeletonKeyToken token; protected SkeletonKeyToken token;
protected HttpServerExchange exchange; protected HttpServerExchange exchange;
protected String redirectUri;
protected KeycloakChallenge challenge; protected KeycloakChallenge challenge;
public OAuthAuthenticator(HttpServerExchange exchange, RealmConfiguration realmInfo, int sslRedirectPort) { public OAuthAuthenticator(HttpServerExchange exchange, RealmConfiguration realmInfo, int sslRedirectPort) {
@ -53,10 +52,6 @@ public class OAuthAuthenticator {
return token; return token;
} }
public String getRedirectUri() {
return redirectUri;
}
protected String getRequestUrl() { protected String getRequestUrl() {
KeycloakUriBuilder uriBuilder = KeycloakUriBuilder.fromUri(exchange.getRequestURI()) KeycloakUriBuilder uriBuilder = KeycloakUriBuilder.fromUri(exchange.getRequestURI())
.replaceQuery(exchange.getQueryString()); .replaceQuery(exchange.getQueryString());
@ -236,6 +231,7 @@ public class OAuthAuthenticator {
if (challenge != null) return challenge; if (challenge != null) return challenge;
AccessTokenResponse tokenResponse = null; AccessTokenResponse tokenResponse = null;
String redirectUri = stripOauthParametersFromRedirect();
try { try {
tokenResponse = TokenGrantRequest.invoke(realmInfo, code, redirectUri); tokenResponse = TokenGrantRequest.invoke(realmInfo, code, redirectUri);
} catch (TokenGrantRequest.HttpFailure failure) { } catch (TokenGrantRequest.HttpFailure failure) {

View file

@ -13,7 +13,7 @@
<properties> <properties>
<resteasy.version>3.0.5.Final</resteasy.version> <resteasy.version>3.0.5.Final</resteasy.version>
<undertow.version>1.0.0.Beta21</undertow.version> <undertow.version>1.0.0.Beta28</undertow.version>
<picketlink.version>2.5.0.Beta6</picketlink.version> <picketlink.version>2.5.0.Beta6</picketlink.version>
<mongo.driver.version>2.11.2</mongo.driver.version> <mongo.driver.version>2.11.2</mongo.driver.version>
<jboss.logging.version>3.1.1.GA</jboss.logging.version> <jboss.logging.version>3.1.1.GA</jboss.logging.version>