keycloak-aplcache
Changes
examples/as7-eap-demo/database-service/src/main/java/org/keycloak/example/oauth/CustomerService.java 2(+1 -1)
examples/as7-eap-demo/database-service/src/main/java/org/keycloak/example/oauth/DataApplication.java 2(+1 -1)
examples/as7-eap-demo/database-service/src/main/java/org/keycloak/example/oauth/ProductService.java 2(+1 -1)
examples/as7-eap-demo/pom.xml 1(+1 -0)
examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java 52(+27 -25)
examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java 12(+6 -6)
examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/AppContextListener.java 57(+57 -0)
examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/CDIResourcesProducer.java 41(+41 -0)
examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java 104(+104 -0)
examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/MessagesChecker.java 34(+34 -0)
examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/RefreshTokenFilter.java 62(+62 -0)
examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/ServletRequestQualifier.java 19(+19 -0)
examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/UserData.java 63(+63 -0)
examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml 7(+7 -0)
examples/wildfly-demo/database-service/src/main/java/org/keycloak/example/oauth/CustomerService.java 2(+1 -1)
examples/wildfly-demo/database-service/src/main/java/org/keycloak/example/oauth/DataApplication.java 2(+1 -1)
examples/wildfly-demo/database-service/src/main/java/org/keycloak/example/oauth/ProductService.java 2(+1 -1)
examples/wildfly-demo/pom.xml 1(+1 -0)
examples/wildfly-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java 52(+27 -25)
examples/wildfly-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java 12(+6 -6)
examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/AppContextListener.java 57(+57 -0)
examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/CDIResourcesProducer.java 41(+41 -0)
examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java 104(+104 -0)
examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/MessagesChecker.java 34(+34 -0)
examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/RefreshTokenFilter.java 62(+62 -0)
examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/ServletRequestQualifier.java 19(+19 -0)
examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/UserData.java 63(+63 -0)
examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml 7(+7 -0)
integration/adapter-core/src/main/java/org/keycloak/adapters/config/AdapterConfigLoader.java 71(+47 -24)
integration/adapter-core/src/main/java/org/keycloak/adapters/config/OAuthClientConfigLoader.java 38(+38 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java 9(+6 -3)
Details
diff --git a/core/src/main/java/org/keycloak/AbstractOAuthClient.java b/core/src/main/java/org/keycloak/AbstractOAuthClient.java
index 9b15f77..aa65ad9 100755
--- a/core/src/main/java/org/keycloak/AbstractOAuthClient.java
+++ b/core/src/main/java/org/keycloak/AbstractOAuthClient.java
@@ -17,6 +17,7 @@ public class AbstractOAuthClient {
protected KeyStore truststore;
protected String authUrl;
protected String codeUrl;
+ protected String scope;
protected String stateCookieName = OAUTH_TOKEN_REQUEST_STATE;
protected String stateCookiePath;
protected boolean isSecure;
@@ -68,6 +69,14 @@ public class AbstractOAuthClient {
this.codeUrl = codeUrl;
}
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
public String getStateCookieName() {
return stateCookieName;
}
diff --git a/core/src/main/java/org/keycloak/adapters/ResourceMetadata.java b/core/src/main/java/org/keycloak/adapters/ResourceMetadata.java
index dc79ff1..dd340b4 100755
--- a/core/src/main/java/org/keycloak/adapters/ResourceMetadata.java
+++ b/core/src/main/java/org/keycloak/adapters/ResourceMetadata.java
@@ -14,6 +14,7 @@ public class ResourceMetadata {
protected String clientKeyPassword;
protected KeyStore truststore;
protected PublicKey realmKey;
+ protected String scope;
public String getResourceName() {
return resourceName;
@@ -78,4 +79,12 @@ public class ResourceMetadata {
public void setRealmKey(PublicKey realmKey) {
this.realmKey = realmKey;
}
+
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
}
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
index fb3a319..46117de 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
@@ -13,7 +13,7 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
"resource", "credentials",
"use-resource-role-mappings",
"enable-cors", "cors-max-age", "cors-allowed-methods",
- "expose-token", "bearer-only",
+ "expose-token", "bearer-only", "scope",
"connection-pool-size",
"allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password",
"client-keystore", "client-keystore-password", "client-key-password"
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/BaseAdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/BaseAdapterConfig.java
index 498ec38..5ab9a72 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/config/BaseAdapterConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/BaseAdapterConfig.java
@@ -2,6 +2,7 @@ package org.keycloak.representations.adapters.config;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonPropertyOrder;
+import org.keycloak.representations.SkeletonKeyScope;
import java.util.HashMap;
import java.util.Map;
@@ -16,7 +17,7 @@ import java.util.Map;
"resource", "credentials",
"use-resource-role-mappings",
"enable-cors", "cors-max-age", "cors-allowed-methods",
- "expose-token", "bearer-only"})
+ "expose-token", "bearer-only", "scope"})
public class BaseAdapterConfig extends BaseRealmConfig {
@JsonProperty("resource")
protected String resource;
@@ -36,6 +37,9 @@ public class BaseAdapterConfig extends BaseRealmConfig {
protected boolean bearerOnly;
@JsonProperty("credentials")
protected Map<String, String> credentials = new HashMap<String, String>();
+ @JsonProperty("scope")
+ protected SkeletonKeyScope scope;
+
public boolean isUseResourceRoleMappings() {
return useResourceRoleMappings;
@@ -108,4 +112,12 @@ public class BaseAdapterConfig extends BaseRealmConfig {
public void setCredentials(Map<String, String> credentials) {
this.credentials = credentials;
}
+
+ public SkeletonKeyScope getScope() {
+ return scope;
+ }
+
+ public void setScope(SkeletonKeyScope scope) {
+ this.scope = scope;
+ }
}
examples/as7-eap-demo/pom.xml 1(+1 -0)
diff --git a/examples/as7-eap-demo/pom.xml b/examples/as7-eap-demo/pom.xml
index dcd6d57..fae3ad4 100755
--- a/examples/as7-eap-demo/pom.xml
+++ b/examples/as7-eap-demo/pom.xml
@@ -38,5 +38,6 @@
<module>product-app</module>
<module>database-service</module>
<module>third-party</module>
+ <module>third-party-cdi</module>
</modules>
</project>
diff --git a/examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java b/examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java
index 121af39..7b8bec2 100755
--- a/examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java
+++ b/examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java
@@ -1,15 +1,19 @@
package org.keycloak.example.oauth;
import org.keycloak.servlet.ServletOAuthClient;
+import org.keycloak.servlet.ServletOAuthClientConfigLoader;
+import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
import java.security.KeyStore;
/**
- * Stupid init code to load up the truststore so we can make appropriate SSL connections
+ * Init code to load up the truststore so we can make appropriate SSL connections
* You really should use a better way of initializing this stuff.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -32,36 +36,34 @@ public class Bootstrap implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
client = new ServletOAuthClient();
-/*
- // hardcoded, WARNING, you should really have a better way of doing this
- // configuration. Either use something like Spring or CDI, or even pull
- // config vales from context-params
- String truststorePath = "${jboss.server.config.dir}/client-truststore.ts";
- String truststorePassword = "password";
- truststorePath = EnvUtil.replace(truststorePath);
- KeyStore truststore = null;
- try
- {
- truststore = loadKeyStore(truststorePath, truststorePassword);
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- client.setTruststore(truststore);
- */
- client.setClientId("third-party");
- client.setPassword("password");
- 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.start();
- sce.getServletContext().setAttribute(ServletOAuthClient.class.getName(), client);
+ ServletContext context = sce.getServletContext();
+ configureClient(context);
+ client.start();
+ context.setAttribute(ServletOAuthClient.class.getName(), client);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
client.stop();
}
+
+ private void configureClient(ServletContext context) {
+ InputStream is = null;
+ String path = context.getInitParameter("keycloak.config.file");
+ if (path == null) {
+ is = context.getResourceAsStream("/WEB-INF/keycloak.json");
+ } else {
+ try {
+ is = new FileInputStream(path);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ ServletOAuthClientConfigLoader loader = new ServletOAuthClientConfigLoader(is);
+ loader.initOAuthClientConfiguration(true);
+ loader.configureServletOAuthClient(client);
+ }
}
diff --git a/examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java b/examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
index 2b4cbd5..a1983dc 100755
--- a/examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
+++ b/examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
@@ -21,11 +21,11 @@ import java.util.List;
*/
public class ProductDatabaseClient {
public static void redirect(HttpServletRequest request, HttpServletResponse response) {
- // 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.
+ // The ServletOAuthClient is obtained by getting a context attribute
+ // that is set in the Bootstrap context listener in this project.
// You really should come up with a better way to initialize
// 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. You can also take a look at third-party-cdi example
ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
try {
oAuthClient.redirectRelative("pull_data.jsp", request, response);
@@ -37,11 +37,11 @@ public class ProductDatabaseClient {
static class TypedList extends ArrayList<String> {}
public static List<String> getProducts(HttpServletRequest request) {
- // 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.
+ // The ServletOAuthClient is obtained by getting a context attribute
+ // that is set in the Bootstrap context listener in this project.
// You really should come up with a better way to initialize
// 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. You can also take a look at third-party-cdi example
ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
String token = null;
try {
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/keycloak.json b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..7241bce
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,12 @@
+{
+ "resource" : "third-party",
+ "auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
+ "code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
+ "ssl-not-required" : true,
+ "credentials" : {
+ "password" : "password"
+ },
+ "scope": {
+ "realm": [ "user" ]
+ }
+}
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party-cdi/pom.xml b/examples/as7-eap-demo/third-party-cdi/pom.xml
new file mode 100755
index 0000000..8df4f5f
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/pom.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.0-alpha-1-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.keycloak.example.as7.demo</groupId>
+ <artifactId>oauth-client-cdi-example</artifactId>
+ <packaging>war</packaging>
+ <name>Simple OAuth Client Using CDI and JSF</name>
+ <description/>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ <version>1.0.1.Final</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.enterprise</groupId>
+ <artifactId>cdi-api</artifactId>
+ <version>1.0-SP4</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.faces</groupId>
+ <artifactId>jboss-jsf-api_2.1_spec</artifactId>
+ <version>2.0.1.Final</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <version>3.1.2.GA</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-servlet-oauth-client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>oauth-client-cdi</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.jboss.as.plugins</groupId>
+ <artifactId>jboss-as-maven-plugin</artifactId>
+ <version>7.4.Final</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/AppContextListener.java b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/AppContextListener.java
new file mode 100644
index 0000000..f84019e
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/AppContextListener.java
@@ -0,0 +1,57 @@
+package org.keycloak.example.oauth;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import javax.inject.Inject;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+
+import org.jboss.logging.Logger;
+import org.keycloak.servlet.ServletOAuthClient;
+import org.keycloak.servlet.ServletOAuthClientConfigLoader;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@WebListener
+public class AppContextListener implements ServletContextListener {
+
+ private static final Logger logger = Logger.getLogger(AppContextListener.class);
+
+ @Inject
+ private ServletOAuthClient oauthClient;
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ ServletContext context = sce.getServletContext();
+
+ InputStream is = null;
+ String path = context.getInitParameter("keycloak.config.file");
+ if (path == null) {
+ is = context.getResourceAsStream("/WEB-INF/keycloak.json");
+ } else {
+ try {
+ is = new FileInputStream(path);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ ServletOAuthClientConfigLoader loader = new ServletOAuthClientConfigLoader(is);
+ loader.initOAuthClientConfiguration(true);
+ loader.configureServletOAuthClient(oauthClient);
+
+ oauthClient.start();
+ logger.info("OAuth client configured and started");
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ oauthClient.stop();
+ logger.info("OAuth client stopped");
+ }
+}
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/CDIResourcesProducer.java b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/CDIResourcesProducer.java
new file mode 100644
index 0000000..fd5e458
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/CDIResourcesProducer.java
@@ -0,0 +1,41 @@
+package org.keycloak.example.oauth;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.inject.Produces;
+import javax.faces.context.FacesContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.keycloak.servlet.ServletOAuthClient;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class CDIResourcesProducer {
+
+ @Produces
+ @RequestScoped
+ public FacesContext produceFacesContext() {
+ return FacesContext.getCurrentInstance();
+ }
+
+ @Produces
+ @RequestScoped
+ @ServletRequestQualifier
+ public HttpServletRequest produceServletRequest() {
+ return (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
+ }
+
+ @Produces
+ @RequestScoped
+ public HttpServletResponse produceServletResponse() {
+ return (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
+ }
+
+ @Produces
+ @ApplicationScoped
+ public ServletOAuthClient produceOAuthClient() {
+ return new ServletOAuthClient();
+ }
+}
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java
new file mode 100755
index 0000000..17f7fd2
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java
@@ -0,0 +1,104 @@
+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.jboss.logging.Logger;
+import org.keycloak.adapters.TokenGrantRequest;
+import org.keycloak.servlet.ServletOAuthClient;
+import org.keycloak.util.JsonSerialization;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+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>
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ * @version $Revision: 1 $
+ */
+@ApplicationScoped
+@Named("databaseClient")
+public class DatabaseClient {
+
+ @Inject
+ @ServletRequestQualifier
+ private HttpServletRequest request;
+
+ @Inject
+ private HttpServletResponse response;
+
+ @Inject
+ private FacesContext facesContext;
+
+ @Inject
+ private ServletOAuthClient oauthClient;
+
+ @Inject
+ private UserData userData;
+
+ private static final Logger logger = Logger.getLogger(DatabaseClient.class);
+
+ public void retrieveAccessToken() {
+ try {
+ oauthClient.redirectRelative("client.jsf", request, response);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static class TypedList extends ArrayList<String> {}
+
+ public void sendCustomersRequest() {
+ List<String> customers = sendRequestToDBApplication("http://localhost:8080/database/customers");
+ userData.setCustomers(customers);
+ }
+
+ public void sendProductsRequest() {
+ List<String> products = sendRequestToDBApplication("http://localhost:8080/database/products");
+ userData.setProducts(products);
+ }
+
+ protected List<String> sendRequestToDBApplication(String dbUri) {
+ HttpClient client = oauthClient.getClient();
+ HttpGet get = new HttpGet(dbUri);
+ try {
+
+ if (userData.isHasAccessToken()) {
+ get.addHeader("Authorization", "Bearer " + userData.getAccessToken());
+ }
+
+ HttpResponse response = client.execute(get);
+ switch (response.getStatusLine().getStatusCode()) {
+ case 200: HttpEntity entity = response.getEntity();
+ InputStream is = entity.getContent();
+ try {
+ return JsonSerialization.readValue(is, TypedList.class);
+ } finally {
+ is.close();
+ }
+ case 401: facesContext.addMessage(null, new FacesMessage("Status: 401. Request not authenticated! You need to retrieve access token first."));
+ break;
+ case 403: facesContext.addMessage(null, new FacesMessage("Status: 403. Access token has insufficient privileges"));
+ break;
+ default: facesContext.addMessage(null, new FacesMessage("Status: " + response.getStatusLine() + ". Not able to retrieve data. See log for details"));
+ logger.warn("Error occured. Status: " + response.getStatusLine());
+ }
+
+ return null;
+ } catch (IOException e) {
+ e.printStackTrace();
+ facesContext.addMessage(null, new FacesMessage("Unknown error. See log for details"));
+ return null;
+ }
+ }
+}
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/MessagesChecker.java b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/MessagesChecker.java
new file mode 100644
index 0000000..e59864f
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/MessagesChecker.java
@@ -0,0 +1,34 @@
+package org.keycloak.example.oauth;
+
+import javax.enterprise.context.RequestScoped;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * This is needed because Faces context is not available in HTTP filters
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@RequestScoped
+@Named("messagesChecker")
+public class MessagesChecker {
+
+ @Inject
+ @ServletRequestQualifier
+ private HttpServletRequest request;
+
+ @Inject
+ private FacesContext facesContext;
+
+ public String getCheckMessage() {
+ String oauthError = (String)request.getAttribute(RefreshTokenFilter.OAUTH_ERROR_ATTR);
+ if (oauthError != null) {
+ facesContext.addMessage(null, new FacesMessage("OAuth error occured: " + oauthError));
+ }
+
+ return null;
+ }
+}
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/RefreshTokenFilter.java b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/RefreshTokenFilter.java
new file mode 100644
index 0000000..7467959
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/RefreshTokenFilter.java
@@ -0,0 +1,62 @@
+package org.keycloak.example.oauth;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.keycloak.adapters.TokenGrantRequest;
+import org.keycloak.servlet.ServletOAuthClient;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@WebFilter(value = "/client.jsf")
+public class RefreshTokenFilter implements Filter {
+
+ public static final String OAUTH_ERROR_ATTR = "oauthErrorAttr";
+
+ @Inject
+ private ServletOAuthClient oauthClient;
+
+ @Inject
+ private UserData userData;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest)req;
+ HttpServletResponse response = (HttpServletResponse)resp;
+ Map<String, String[]> reqParams = request.getParameterMap();
+
+ if (reqParams.containsKey("code")) {
+ try {
+ String accessToken = oauthClient.getBearerToken(request);
+ userData.setAccessToken(accessToken);
+ } catch (TokenGrantRequest.HttpFailure e) {
+ throw new ServletException(e);
+ }
+ } else if (reqParams.containsKey("error")) {
+ String oauthError = reqParams.get("error")[0];
+ request.setAttribute(OAUTH_ERROR_ATTR, oauthError);
+ }
+
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy() {
+ }
+}
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/ServletRequestQualifier.java b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/ServletRequestQualifier.java
new file mode 100644
index 0000000..5f7edca
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/ServletRequestQualifier.java
@@ -0,0 +1,19 @@
+package org.keycloak.example.oauth;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+/**
+ * This is needed to have same code working in AS7 and Wildfly. In Wildfly is HttpServletRequest injected automatically, in AS7 it's not
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
+public @interface ServletRequestQualifier {
+}
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/UserData.java b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/UserData.java
new file mode 100644
index 0000000..6571b18
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/UserData.java
@@ -0,0 +1,63 @@
+package org.keycloak.example.oauth;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.enterprise.context.SessionScoped;
+import javax.inject.Named;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@SessionScoped
+@Named("userData")
+public class UserData implements Serializable {
+
+ private String accessToken;
+ private List<String> products;
+ private List<String> customers;
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ public boolean isHasAccessToken() {
+ return accessToken != null;
+ }
+
+ public String getAccessTokenAvailabilityMessage() {
+ StringBuilder builder = new StringBuilder("Access token ");
+ if (!isHasAccessToken()) {
+ builder.append("not ");
+ }
+ return builder.append("available!").toString();
+ }
+
+ public List<String> getProducts() {
+ return products;
+ }
+
+ public void setProducts(List<String> products) {
+ this.products = products;
+ }
+
+ public boolean isHasProducts() {
+ return products != null;
+ }
+
+ public List<String> getCustomers() {
+ return customers;
+ }
+
+ public void setCustomers(List<String> customers) {
+ this.customers = customers;
+ }
+
+ public boolean isHasCustomers() {
+ return customers != null;
+ }
+}
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/webapp/client.xhtml b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/client.xhtml
new file mode 100644
index 0000000..7c4a8dd
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/client.xhtml
@@ -0,0 +1,37 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core">
+ <body>
+ <h1>Third Party App That Pulls Data Using OAuth</h1>
+ <h:form>
+ #{userData.accessTokenAvailabilityMessage}
+ <br />
+ <h:commandButton id="retrieve_token" value="Retrieve/refresh access token" action="#{databaseClient.retrieveAccessToken}"/>
+ <h:commandButton id="products_request" value="Load products list" action="#{databaseClient.sendProductsRequest}"/>
+ <h:commandButton id="customers_request" value="Load customers list" action="#{databaseClient.sendCustomersRequest}"/>
+ </h:form>
+
+ <ui:fragment rendered="#{userData.hasProducts}">
+ <hr />
+ <h3>Products data available</h3>
+ <ui:repeat value="#{userData.products}" var="product">
+ #{product}<br/>
+ </ui:repeat>
+ </ui:fragment>
+
+ <ui:fragment rendered="#{userData.hasCustomers}">
+ <hr />
+ <h3>Customers data available</h3>
+ <ui:repeat value="#{userData.customers}" var="customer">
+ #{customer}<br/>
+ </ui:repeat>
+ </ui:fragment>
+
+ <div style="color: red">
+ #{messagesChecker.checkMessage}
+ <h:messages globalOnly="true"/>
+ </div>
+ </body>
+</html>
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/webapp/index.html b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/index.html
new file mode 100644
index 0000000..7b641f7
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/index.html
@@ -0,0 +1,5 @@
+<html>
+ <head>
+ <meta http-equiv="Refresh" content="0; URL=client.jsf">
+ </head>
+</html>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/beans.xml b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000..c4feade
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,23 @@
+<!--
+JBoss, Home of Professional Open Source
+Copyright 2013, Red Hat, Inc. and/or its affiliates, and individual
+contributors by the @authors tag. See the copyright.txt in the
+distribution for a full listing of individual contributors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<!-- Marker file indicating CDI should be enabled -->
+<beans xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+</beans>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/faces-config.xml b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/faces-config.xml
new file mode 100644
index 0000000..10787a0
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/faces-config.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+JBoss, Home of Professional Open Source
+Copyright 2013, Red Hat, Inc. and/or its affiliates, and individual
+contributors by the @authors tag. See the copyright.txt in the
+distribution for a full listing of individual contributors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<!-- Marker file indicating JSF should be enabled -->
+<faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
+
+</faces-config>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
new file mode 100755
index 0000000..c54e4ab
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -0,0 +1,7 @@
+<jboss-deployment-structure>
+ <deployment>
+ <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
+ <dependencies>
+ </dependencies>
+ </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/keycloak.json b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..7241bce
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,12 @@
+{
+ "resource" : "third-party",
+ "auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
+ "code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
+ "ssl-not-required" : true,
+ "credentials" : {
+ "password" : "password"
+ },
+ "scope": {
+ "realm": [ "user" ]
+ }
+}
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/web.xml b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..93e1ef6
--- /dev/null
+++ b/examples/as7-eap-demo/third-party-cdi/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>oauth-client-cdi</module-name>
+
+ <!--
+ <security-constraint>
+ <web-resource-collection>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <user-data-constraint>
+ <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+ </user-data-constraint>
+ </security-constraint>
+ -->
+
+</web-app>
examples/wildfly-demo/pom.xml 1(+1 -0)
diff --git a/examples/wildfly-demo/pom.xml b/examples/wildfly-demo/pom.xml
index 1d86e9e..95444eb 100755
--- a/examples/wildfly-demo/pom.xml
+++ b/examples/wildfly-demo/pom.xml
@@ -39,5 +39,6 @@
<module>product-app</module>
<module>database-service</module>
<module>third-party</module>
+ <module>third-party-cdi</module>
</modules>
</project>
diff --git a/examples/wildfly-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java b/examples/wildfly-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java
index 121af39..7b8bec2 100755
--- a/examples/wildfly-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java
+++ b/examples/wildfly-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java
@@ -1,15 +1,19 @@
package org.keycloak.example.oauth;
import org.keycloak.servlet.ServletOAuthClient;
+import org.keycloak.servlet.ServletOAuthClientConfigLoader;
+import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
import java.security.KeyStore;
/**
- * Stupid init code to load up the truststore so we can make appropriate SSL connections
+ * Init code to load up the truststore so we can make appropriate SSL connections
* You really should use a better way of initializing this stuff.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -32,36 +36,34 @@ public class Bootstrap implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
client = new ServletOAuthClient();
-/*
- // hardcoded, WARNING, you should really have a better way of doing this
- // configuration. Either use something like Spring or CDI, or even pull
- // config vales from context-params
- String truststorePath = "${jboss.server.config.dir}/client-truststore.ts";
- String truststorePassword = "password";
- truststorePath = EnvUtil.replace(truststorePath);
- KeyStore truststore = null;
- try
- {
- truststore = loadKeyStore(truststorePath, truststorePassword);
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- client.setTruststore(truststore);
- */
- client.setClientId("third-party");
- client.setPassword("password");
- 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.start();
- sce.getServletContext().setAttribute(ServletOAuthClient.class.getName(), client);
+ ServletContext context = sce.getServletContext();
+ configureClient(context);
+ client.start();
+ context.setAttribute(ServletOAuthClient.class.getName(), client);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
client.stop();
}
+
+ private void configureClient(ServletContext context) {
+ InputStream is = null;
+ String path = context.getInitParameter("keycloak.config.file");
+ if (path == null) {
+ is = context.getResourceAsStream("/WEB-INF/keycloak.json");
+ } else {
+ try {
+ is = new FileInputStream(path);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ ServletOAuthClientConfigLoader loader = new ServletOAuthClientConfigLoader(is);
+ loader.initOAuthClientConfiguration(true);
+ loader.configureServletOAuthClient(client);
+ }
}
diff --git a/examples/wildfly-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java b/examples/wildfly-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
index 2b4cbd5..a1983dc 100755
--- a/examples/wildfly-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
+++ b/examples/wildfly-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
@@ -21,11 +21,11 @@ import java.util.List;
*/
public class ProductDatabaseClient {
public static void redirect(HttpServletRequest request, HttpServletResponse response) {
- // 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.
+ // The ServletOAuthClient is obtained by getting a context attribute
+ // that is set in the Bootstrap context listener in this project.
// You really should come up with a better way to initialize
// 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. You can also take a look at third-party-cdi example
ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
try {
oAuthClient.redirectRelative("pull_data.jsp", request, response);
@@ -37,11 +37,11 @@ public class ProductDatabaseClient {
static class TypedList extends ArrayList<String> {}
public static List<String> getProducts(HttpServletRequest request) {
- // 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.
+ // The ServletOAuthClient is obtained by getting a context attribute
+ // that is set in the Bootstrap context listener in this project.
// You really should come up with a better way to initialize
// 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. You can also take a look at third-party-cdi example
ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
String token = null;
try {
diff --git a/examples/wildfly-demo/third-party/src/main/webapp/WEB-INF/keycloak.json b/examples/wildfly-demo/third-party/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..7241bce
--- /dev/null
+++ b/examples/wildfly-demo/third-party/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,12 @@
+{
+ "resource" : "third-party",
+ "auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
+ "code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
+ "ssl-not-required" : true,
+ "credentials" : {
+ "password" : "password"
+ },
+ "scope": {
+ "realm": [ "user" ]
+ }
+}
\ No newline at end of file
diff --git a/examples/wildfly-demo/third-party-cdi/pom.xml b/examples/wildfly-demo/third-party-cdi/pom.xml
new file mode 100755
index 0000000..27784e3
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/pom.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.0-alpha-1-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.keycloak.example.wildfly.demo</groupId>
+ <artifactId>oauth-client-cdi-example</artifactId>
+ <packaging>war</packaging>
+ <name>Simple OAuth Client Using CDI and JSF</name>
+ <description/>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ <version>1.0.1.Final</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.enterprise</groupId>
+ <artifactId>cdi-api</artifactId>
+ <version>1.0-SP4</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.faces</groupId>
+ <artifactId>jboss-jsf-api_2.1_spec</artifactId>
+ <version>2.0.1.Final</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <version>3.1.2.GA</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-servlet-oauth-client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>oauth-client-cdi</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.jboss.as.plugins</groupId>
+ <artifactId>jboss-as-maven-plugin</artifactId>
+ <version>7.4.Final</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/AppContextListener.java b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/AppContextListener.java
new file mode 100644
index 0000000..f84019e
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/AppContextListener.java
@@ -0,0 +1,57 @@
+package org.keycloak.example.oauth;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import javax.inject.Inject;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+
+import org.jboss.logging.Logger;
+import org.keycloak.servlet.ServletOAuthClient;
+import org.keycloak.servlet.ServletOAuthClientConfigLoader;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@WebListener
+public class AppContextListener implements ServletContextListener {
+
+ private static final Logger logger = Logger.getLogger(AppContextListener.class);
+
+ @Inject
+ private ServletOAuthClient oauthClient;
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ ServletContext context = sce.getServletContext();
+
+ InputStream is = null;
+ String path = context.getInitParameter("keycloak.config.file");
+ if (path == null) {
+ is = context.getResourceAsStream("/WEB-INF/keycloak.json");
+ } else {
+ try {
+ is = new FileInputStream(path);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ ServletOAuthClientConfigLoader loader = new ServletOAuthClientConfigLoader(is);
+ loader.initOAuthClientConfiguration(true);
+ loader.configureServletOAuthClient(oauthClient);
+
+ oauthClient.start();
+ logger.info("OAuth client configured and started");
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ oauthClient.stop();
+ logger.info("OAuth client stopped");
+ }
+}
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/CDIResourcesProducer.java b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/CDIResourcesProducer.java
new file mode 100644
index 0000000..fd5e458
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/CDIResourcesProducer.java
@@ -0,0 +1,41 @@
+package org.keycloak.example.oauth;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.inject.Produces;
+import javax.faces.context.FacesContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.keycloak.servlet.ServletOAuthClient;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class CDIResourcesProducer {
+
+ @Produces
+ @RequestScoped
+ public FacesContext produceFacesContext() {
+ return FacesContext.getCurrentInstance();
+ }
+
+ @Produces
+ @RequestScoped
+ @ServletRequestQualifier
+ public HttpServletRequest produceServletRequest() {
+ return (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
+ }
+
+ @Produces
+ @RequestScoped
+ public HttpServletResponse produceServletResponse() {
+ return (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
+ }
+
+ @Produces
+ @ApplicationScoped
+ public ServletOAuthClient produceOAuthClient() {
+ return new ServletOAuthClient();
+ }
+}
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java
new file mode 100755
index 0000000..17f7fd2
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java
@@ -0,0 +1,104 @@
+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.jboss.logging.Logger;
+import org.keycloak.adapters.TokenGrantRequest;
+import org.keycloak.servlet.ServletOAuthClient;
+import org.keycloak.util.JsonSerialization;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+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>
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ * @version $Revision: 1 $
+ */
+@ApplicationScoped
+@Named("databaseClient")
+public class DatabaseClient {
+
+ @Inject
+ @ServletRequestQualifier
+ private HttpServletRequest request;
+
+ @Inject
+ private HttpServletResponse response;
+
+ @Inject
+ private FacesContext facesContext;
+
+ @Inject
+ private ServletOAuthClient oauthClient;
+
+ @Inject
+ private UserData userData;
+
+ private static final Logger logger = Logger.getLogger(DatabaseClient.class);
+
+ public void retrieveAccessToken() {
+ try {
+ oauthClient.redirectRelative("client.jsf", request, response);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static class TypedList extends ArrayList<String> {}
+
+ public void sendCustomersRequest() {
+ List<String> customers = sendRequestToDBApplication("http://localhost:8080/database/customers");
+ userData.setCustomers(customers);
+ }
+
+ public void sendProductsRequest() {
+ List<String> products = sendRequestToDBApplication("http://localhost:8080/database/products");
+ userData.setProducts(products);
+ }
+
+ protected List<String> sendRequestToDBApplication(String dbUri) {
+ HttpClient client = oauthClient.getClient();
+ HttpGet get = new HttpGet(dbUri);
+ try {
+
+ if (userData.isHasAccessToken()) {
+ get.addHeader("Authorization", "Bearer " + userData.getAccessToken());
+ }
+
+ HttpResponse response = client.execute(get);
+ switch (response.getStatusLine().getStatusCode()) {
+ case 200: HttpEntity entity = response.getEntity();
+ InputStream is = entity.getContent();
+ try {
+ return JsonSerialization.readValue(is, TypedList.class);
+ } finally {
+ is.close();
+ }
+ case 401: facesContext.addMessage(null, new FacesMessage("Status: 401. Request not authenticated! You need to retrieve access token first."));
+ break;
+ case 403: facesContext.addMessage(null, new FacesMessage("Status: 403. Access token has insufficient privileges"));
+ break;
+ default: facesContext.addMessage(null, new FacesMessage("Status: " + response.getStatusLine() + ". Not able to retrieve data. See log for details"));
+ logger.warn("Error occured. Status: " + response.getStatusLine());
+ }
+
+ return null;
+ } catch (IOException e) {
+ e.printStackTrace();
+ facesContext.addMessage(null, new FacesMessage("Unknown error. See log for details"));
+ return null;
+ }
+ }
+}
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/MessagesChecker.java b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/MessagesChecker.java
new file mode 100644
index 0000000..e59864f
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/MessagesChecker.java
@@ -0,0 +1,34 @@
+package org.keycloak.example.oauth;
+
+import javax.enterprise.context.RequestScoped;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * This is needed because Faces context is not available in HTTP filters
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@RequestScoped
+@Named("messagesChecker")
+public class MessagesChecker {
+
+ @Inject
+ @ServletRequestQualifier
+ private HttpServletRequest request;
+
+ @Inject
+ private FacesContext facesContext;
+
+ public String getCheckMessage() {
+ String oauthError = (String)request.getAttribute(RefreshTokenFilter.OAUTH_ERROR_ATTR);
+ if (oauthError != null) {
+ facesContext.addMessage(null, new FacesMessage("OAuth error occured: " + oauthError));
+ }
+
+ return null;
+ }
+}
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/RefreshTokenFilter.java b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/RefreshTokenFilter.java
new file mode 100644
index 0000000..7467959
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/RefreshTokenFilter.java
@@ -0,0 +1,62 @@
+package org.keycloak.example.oauth;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.keycloak.adapters.TokenGrantRequest;
+import org.keycloak.servlet.ServletOAuthClient;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@WebFilter(value = "/client.jsf")
+public class RefreshTokenFilter implements Filter {
+
+ public static final String OAUTH_ERROR_ATTR = "oauthErrorAttr";
+
+ @Inject
+ private ServletOAuthClient oauthClient;
+
+ @Inject
+ private UserData userData;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest)req;
+ HttpServletResponse response = (HttpServletResponse)resp;
+ Map<String, String[]> reqParams = request.getParameterMap();
+
+ if (reqParams.containsKey("code")) {
+ try {
+ String accessToken = oauthClient.getBearerToken(request);
+ userData.setAccessToken(accessToken);
+ } catch (TokenGrantRequest.HttpFailure e) {
+ throw new ServletException(e);
+ }
+ } else if (reqParams.containsKey("error")) {
+ String oauthError = reqParams.get("error")[0];
+ request.setAttribute(OAUTH_ERROR_ATTR, oauthError);
+ }
+
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy() {
+ }
+}
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/ServletRequestQualifier.java b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/ServletRequestQualifier.java
new file mode 100644
index 0000000..5f7edca
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/ServletRequestQualifier.java
@@ -0,0 +1,19 @@
+package org.keycloak.example.oauth;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+/**
+ * This is needed to have same code working in AS7 and Wildfly. In Wildfly is HttpServletRequest injected automatically, in AS7 it's not
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
+public @interface ServletRequestQualifier {
+}
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/UserData.java b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/UserData.java
new file mode 100644
index 0000000..6571b18
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/java/org/keycloak/example/oauth/UserData.java
@@ -0,0 +1,63 @@
+package org.keycloak.example.oauth;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.enterprise.context.SessionScoped;
+import javax.inject.Named;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@SessionScoped
+@Named("userData")
+public class UserData implements Serializable {
+
+ private String accessToken;
+ private List<String> products;
+ private List<String> customers;
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ public boolean isHasAccessToken() {
+ return accessToken != null;
+ }
+
+ public String getAccessTokenAvailabilityMessage() {
+ StringBuilder builder = new StringBuilder("Access token ");
+ if (!isHasAccessToken()) {
+ builder.append("not ");
+ }
+ return builder.append("available!").toString();
+ }
+
+ public List<String> getProducts() {
+ return products;
+ }
+
+ public void setProducts(List<String> products) {
+ this.products = products;
+ }
+
+ public boolean isHasProducts() {
+ return products != null;
+ }
+
+ public List<String> getCustomers() {
+ return customers;
+ }
+
+ public void setCustomers(List<String> customers) {
+ this.customers = customers;
+ }
+
+ public boolean isHasCustomers() {
+ return customers != null;
+ }
+}
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/webapp/client.xhtml b/examples/wildfly-demo/third-party-cdi/src/main/webapp/client.xhtml
new file mode 100644
index 0000000..7c4a8dd
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/webapp/client.xhtml
@@ -0,0 +1,37 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core">
+ <body>
+ <h1>Third Party App That Pulls Data Using OAuth</h1>
+ <h:form>
+ #{userData.accessTokenAvailabilityMessage}
+ <br />
+ <h:commandButton id="retrieve_token" value="Retrieve/refresh access token" action="#{databaseClient.retrieveAccessToken}"/>
+ <h:commandButton id="products_request" value="Load products list" action="#{databaseClient.sendProductsRequest}"/>
+ <h:commandButton id="customers_request" value="Load customers list" action="#{databaseClient.sendCustomersRequest}"/>
+ </h:form>
+
+ <ui:fragment rendered="#{userData.hasProducts}">
+ <hr />
+ <h3>Products data available</h3>
+ <ui:repeat value="#{userData.products}" var="product">
+ #{product}<br/>
+ </ui:repeat>
+ </ui:fragment>
+
+ <ui:fragment rendered="#{userData.hasCustomers}">
+ <hr />
+ <h3>Customers data available</h3>
+ <ui:repeat value="#{userData.customers}" var="customer">
+ #{customer}<br/>
+ </ui:repeat>
+ </ui:fragment>
+
+ <div style="color: red">
+ #{messagesChecker.checkMessage}
+ <h:messages globalOnly="true"/>
+ </div>
+ </body>
+</html>
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/webapp/index.html b/examples/wildfly-demo/third-party-cdi/src/main/webapp/index.html
new file mode 100644
index 0000000..7b641f7
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/webapp/index.html
@@ -0,0 +1,5 @@
+<html>
+ <head>
+ <meta http-equiv="Refresh" content="0; URL=client.jsf">
+ </head>
+</html>
\ No newline at end of file
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/beans.xml b/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000..c4feade
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,23 @@
+<!--
+JBoss, Home of Professional Open Source
+Copyright 2013, Red Hat, Inc. and/or its affiliates, and individual
+contributors by the @authors tag. See the copyright.txt in the
+distribution for a full listing of individual contributors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<!-- Marker file indicating CDI should be enabled -->
+<beans xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+</beans>
\ No newline at end of file
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/faces-config.xml b/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/faces-config.xml
new file mode 100644
index 0000000..10787a0
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/faces-config.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+JBoss, Home of Professional Open Source
+Copyright 2013, Red Hat, Inc. and/or its affiliates, and individual
+contributors by the @authors tag. See the copyright.txt in the
+distribution for a full listing of individual contributors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<!-- Marker file indicating JSF should be enabled -->
+<faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
+
+</faces-config>
\ No newline at end of file
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
new file mode 100755
index 0000000..c54e4ab
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -0,0 +1,7 @@
+<jboss-deployment-structure>
+ <deployment>
+ <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
+ <dependencies>
+ </dependencies>
+ </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/keycloak.json b/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..7241bce
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,12 @@
+{
+ "resource" : "third-party",
+ "auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
+ "code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
+ "ssl-not-required" : true,
+ "credentials" : {
+ "password" : "password"
+ },
+ "scope": {
+ "realm": [ "user" ]
+ }
+}
\ No newline at end of file
diff --git a/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/web.xml b/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..93e1ef6
--- /dev/null
+++ b/examples/wildfly-demo/third-party-cdi/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>oauth-client-cdi</module-name>
+
+ <!--
+ <security-constraint>
+ <web-resource-collection>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <user-data-constraint>
+ <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+ </user-data-constraint>
+ </security-constraint>
+ -->
+
+</web-app>
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/config/AdapterConfigLoader.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/config/AdapterConfigLoader.java
index 1b4245f..8733ff9 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/config/AdapterConfigLoader.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/config/AdapterConfigLoader.java
@@ -2,7 +2,10 @@ package org.keycloak.adapters.config;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.keycloak.representations.SkeletonKeyScope;
+import org.keycloak.util.Base64Url;
import org.keycloak.util.EnvUtil;
+import org.keycloak.util.JsonSerialization;
import org.keycloak.util.PemUtils;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.representations.adapters.config.AdapterConfig;
@@ -35,29 +38,8 @@ public class AdapterConfigLoader {
}
public void init() {
- String truststorePath = adapterConfig.getTruststore();
- if (truststorePath != null) {
- truststorePath = EnvUtil.replace(truststorePath);
- String truststorePassword = adapterConfig.getTruststorePassword();
- truststorePath = null;
- try {
- this.truststore = loadKeyStore(truststorePath, truststorePassword);
- } catch (Exception e) {
- throw new RuntimeException("Failed to load truststore", e);
- }
- }
- String clientKeystore = adapterConfig.getClientKeystore();
- String clientKeyPassword = null;
- if (clientKeystore != null) {
- clientKeystore = EnvUtil.replace(clientKeystore);
- String clientKeystorePassword = adapterConfig.getClientKeystorePassword();
- clientCertKeystore = null;
- try {
- clientCertKeystore = loadKeyStore(clientKeystore, clientKeystorePassword);
- } catch (Exception e) {
- throw new RuntimeException("Failed to load keystore", e);
- }
- }
+ initTruststore();
+ initClientKeystore();
String realm = adapterConfig.getRealm();
if (realm == null) throw new RuntimeException("Must set 'realm' in config");
@@ -81,10 +63,15 @@ public class AdapterConfigLoader {
resourceMetadata.setResourceName(resource);
resourceMetadata.setRealmKey(realmKey);
resourceMetadata.setClientKeystore(clientCertKeystore);
- clientKeyPassword = adapterConfig.getClientKeyPassword();
+ String clientKeyPassword = adapterConfig.getClientKeyPassword();
resourceMetadata.setClientKeyPassword(clientKeyPassword);
resourceMetadata.setTruststore(this.truststore);
+ if (adapterConfig.getScope() != null) {
+ String scope = encodeScope(adapterConfig.getScope());
+ resourceMetadata.setScope(scope);
+ }
+
}
public AdapterConfig getAdapterConfig() {
@@ -113,4 +100,40 @@ public class AdapterConfigLoader {
throw new RuntimeException(e);
}
}
+
+ protected void initTruststore() {
+ String truststorePath = adapterConfig.getTruststore();
+ if (truststorePath != null) {
+ truststorePath = EnvUtil.replace(truststorePath);
+ String truststorePassword = adapterConfig.getTruststorePassword();
+ try {
+ this.truststore = loadKeyStore(truststorePath, truststorePassword);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to load truststore", e);
+ }
+ }
+ }
+
+ protected void initClientKeystore() {
+ String clientKeystore = adapterConfig.getClientKeystore();
+ if (clientKeystore != null) {
+ clientKeystore = EnvUtil.replace(clientKeystore);
+ String clientKeystorePassword = adapterConfig.getClientKeystorePassword();
+ clientCertKeystore = null;
+ try {
+ clientCertKeystore = loadKeyStore(clientKeystore, clientKeystorePassword);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to load keystore", e);
+ }
+ }
+ }
+
+ protected String encodeScope(SkeletonKeyScope scope) {
+ try {
+ byte[] scopeBytes = JsonSerialization.writeValueAsBytes(scope);
+ return Base64Url.encode(scopeBytes);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/config/OAuthClientConfigLoader.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/config/OAuthClientConfigLoader.java
new file mode 100644
index 0000000..98101b2
--- /dev/null
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/config/OAuthClientConfigLoader.java
@@ -0,0 +1,38 @@
+package org.keycloak.adapters.config;
+
+import java.io.InputStream;
+
+import org.keycloak.AbstractOAuthClient;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class OAuthClientConfigLoader extends RealmConfigurationLoader {
+
+ public OAuthClientConfigLoader() {
+ }
+
+ public OAuthClientConfigLoader(InputStream is) {
+ super(is);
+ }
+
+ /**
+ * For now, configure just things supported by AbstractOAuthClient
+ */
+ public void initOAuthClientConfiguration() {
+ initTruststore();
+ initClientKeystore();
+ }
+
+ public void configureOAuthClient(AbstractOAuthClient oauthClient) {
+ oauthClient.setClientId(adapterConfig.getResource());
+ oauthClient.setPassword(adapterConfig.getCredentials().get("password"));
+ oauthClient.setAuthUrl(adapterConfig.getAuthUrl());
+ oauthClient.setCodeUrl(adapterConfig.getCodeUrl());
+ oauthClient.setTruststore(truststore);
+ if (adapterConfig.getScope() != null) {
+ String scope = encodeScope(adapterConfig.getScope());
+ oauthClient.setScope(scope);
+ }
+ }
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
index 8d21b67..4394472 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
@@ -138,12 +138,15 @@ public class ServletOAuthLogin {
if (port != 443) secureUrl.port(port);
url = secureUrl.build().toString();
}
- return realmInfo.getAuthUrl().clone()
+ KeycloakUriBuilder uriBuilder = realmInfo.getAuthUrl().clone()
.queryParam("client_id", realmInfo.getMetadata().getResourceName())
.queryParam("redirect_uri", url)
.queryParam("state", state)
- .queryParam("login", "true")
- .build().toString();
+ .queryParam("login", "true");
+ if (realmInfo.getMetadata().getScope() != null) {
+ uriBuilder.queryParam("scope", realmInfo.getMetadata().getScope());
+ }
+ return uriBuilder.build().toString();
}
protected static final AtomicLong counter = new AtomicLong();
diff --git a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
index 8e0f640..1858caa 100755
--- a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
+++ b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
@@ -18,6 +18,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
+import java.net.URL;
/**
* Helper code to obtain oauth access tokens via browser redirects
@@ -87,11 +88,15 @@ public class JaxrsOAuthClient extends AbstractOAuthClient {
state += "#" + path;
}
- URI url = UriBuilder.fromUri(authUrl)
+ UriBuilder uriBuilder = UriBuilder.fromUri(authUrl)
.queryParam("client_id", clientId)
.queryParam("redirect_uri", redirectUri)
- .queryParam("state", state)
- .build();
+ .queryParam("state", state);
+ if (scope != null) {
+ uriBuilder.queryParam("scope", scope);
+ }
+ URI url = uriBuilder.build();
+
NewCookie cookie = new NewCookie(getStateCookieName(), state, getStateCookiePath(uriInfo), null, null, -1, isSecure, true);
logger.debug("NewCookie: " + cookie.toString());
logger.debug("Oauth Redirect to: " + url);
diff --git a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
index 8799bab..c8259c4 100755
--- a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
+++ b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
@@ -84,11 +84,15 @@ public class ServletOAuthClient extends AbstractOAuthClient {
public void redirect(String redirectUri, HttpServletRequest request, HttpServletResponse response) throws IOException {
String state = getStateCode();
- URI url = KeycloakUriBuilder.fromUri(authUrl)
+ KeycloakUriBuilder uriBuilder = KeycloakUriBuilder.fromUri(authUrl)
.queryParam("client_id", clientId)
.queryParam("redirect_uri", redirectUri)
- .queryParam("state", state)
- .build();
+ .queryParam("state", state);
+ if (scope != null) {
+ uriBuilder.queryParam("scope", scope);
+ }
+ URI url = uriBuilder.build();
+
String stateCookiePath = this.stateCookiePath;
if (stateCookiePath == null) stateCookiePath = request.getContextPath();
if (stateCookiePath.equals("")) stateCookiePath = "/";
diff --git a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientConfigLoader.java b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientConfigLoader.java
new file mode 100644
index 0000000..668a50c
--- /dev/null
+++ b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientConfigLoader.java
@@ -0,0 +1,36 @@
+package org.keycloak.servlet;
+
+import java.io.InputStream;
+
+import org.keycloak.adapters.config.OAuthClientConfigLoader;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ServletOAuthClientConfigLoader extends OAuthClientConfigLoader {
+
+ public ServletOAuthClientConfigLoader() {
+ }
+
+ public ServletOAuthClientConfigLoader(InputStream is) {
+ super(is);
+ }
+
+ /**
+ * For now, configure just things supported by ServletOAuthClient
+ * @param setupClient
+ */
+ public void initOAuthClientConfiguration(boolean setupClient) {
+ initOAuthClientConfiguration();
+ if (setupClient) {
+ initClient();
+ }
+ }
+
+ public void configureServletOAuthClient(ServletOAuthClient oauthClient) {
+ configureOAuthClient(oauthClient);
+ if (client != null) {
+ oauthClient.setClient(client);
+ }
+ }
+}