keycloak-aplcache

Changes

Details

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/pom.xml b/examples/as7-eap-demo/third-party/pom.xml
index bda3d9f..89372bc 100755
--- a/examples/as7-eap-demo/third-party/pom.xml
+++ b/examples/as7-eap-demo/third-party/pom.xml
@@ -22,24 +22,6 @@
             <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>
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
new file mode 100755
index 0000000..7b8bec2
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/Bootstrap.java
@@ -0,0 +1,69 @@
+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;
+
+/**
+ * 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>
+ * @version $Revision: 1 $
+ */
+public class Bootstrap implements ServletContextListener {
+
+    private ServletOAuthClient client;
+
+    private static KeyStore loadKeyStore(String filename, String password) throws Exception {
+        KeyStore trustStore = KeyStore.getInstance(KeyStore
+                .getDefaultType());
+        File truststoreFile = new File(filename);
+        FileInputStream trustStream = new FileInputStream(truststoreFile);
+        trustStore.load(trustStream, password.toCharArray());
+        trustStream.close();
+        return trustStore;
+    }
+
+    @Override
+    public void contextInitialized(ServletContextEvent sce) {
+        client = new ServletOAuthClient();
+        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
new file mode 100755
index 0000000..a1983dc
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
@@ -0,0 +1,72 @@
+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.adapters.TokenGrantRequest;
+import org.keycloak.servlet.ServletOAuthClient;
+import org.keycloak.util.JsonSerialization;
+
+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>
+ * @version $Revision: 1 $
+ */
+public class ProductDatabaseClient {
+    public static void redirect(HttpServletRequest request, HttpServletResponse response) {
+        // 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. 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);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    static class TypedList extends ArrayList<String> {}
+
+    public static List<String> getProducts(HttpServletRequest request) {
+        // 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. You can also take a look at third-party-cdi example
+        ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
+        String token = null;
+        try {
+            token = oAuthClient.getBearerToken(request);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } catch (TokenGrantRequest.HttpFailure failure) {
+            throw new RuntimeException(failure);
+        }
+
+        HttpClient client = oAuthClient.getClient();
+
+        HttpGet get = new HttpGet("http://localhost:8080/database/products");
+        get.addHeader("Authorization", "Bearer " + token);
+        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);
+        }
+    }
+}
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/index.html b/examples/as7-eap-demo/third-party/src/main/webapp/index.html
index 7b641f7..dbd7d7a 100644
--- a/examples/as7-eap-demo/third-party/src/main/webapp/index.html
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/index.html
@@ -1,5 +1,6 @@
 <html>
-    <head>
-        <meta http-equiv="Refresh" content="0; URL=client.jsf">
-    </head>
+<body>
+<h1>Third Party App That Pulls Data Using OAuth</h1>
+<a href="redirect.jsp">Pull Data</a>
+</body>
 </html>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/pull_data.jsp b/examples/as7-eap-demo/third-party/src/main/webapp/pull_data.jsp
new file mode 100755
index 0000000..a64f674
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/pull_data.jsp
@@ -0,0 +1,22 @@
+<%@ page import="org.keycloak.example.oauth.ProductDatabaseClient" %>
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1"%>
+<html>
+<head>
+    <title>Pull Page</title>
+</head>
+<body>
+<h2>Pulled Product Listing</h2>
+<%
+java.util.List<String> list = ProductDatabaseClient.getProducts(request);
+for (String prod : list)
+{
+   out.print("<p>");
+   out.print(prod);
+   out.println("</p>");
+
+}
+%>
+<br><br>
+</body>
+</html>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/redirect.jsp b/examples/as7-eap-demo/third-party/src/main/webapp/redirect.jsp
new file mode 100755
index 0000000..c74a9ae
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/redirect.jsp
@@ -0,0 +1,3 @@
+<%@ page import="org.keycloak.example.oauth.ProductDatabaseClient" %><%
+   ProductDatabaseClient.redirect(request, response);
+%>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml
index d1762e2..958839d 100755
--- a/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml
@@ -6,6 +6,9 @@
 
 	<module-name>oauth-client</module-name>
 
+    <listener>
+        <listener-class>org.keycloak.example.oauth.Bootstrap</listener-class>
+    </listener>
     <!--
     <security-constraint>
         <web-resource-collection>
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/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/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/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>
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>