keycloak-aplcache

Merge pull request #898 from gerbermichi/master Fix the

12/22/2014 5:01:26 PM

Changes

Details

diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-undertow-adapter/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-undertow-adapter/main/module.xml
index 774b279..9d19d40 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-undertow-adapter/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-undertow-adapter/main/module.xml
@@ -35,6 +35,7 @@
         <module name="org.apache.httpcomponents" />
         <module name="javax.servlet.api"/>
         <module name="org.jboss.logging"/>
+        <module name="org.jboss.xnio"/>
         <module name="io.undertow.core"/>
         <module name="io.undertow.servlet"/>
         <module name="org.keycloak.keycloak-adapter-core"/>
diff --git a/examples/demo-template/pom.xml b/examples/demo-template/pom.xml
index 7c33c28..d6f3c12 100755
--- a/examples/demo-template/pom.xml
+++ b/examples/demo-template/pom.xml
@@ -34,6 +34,7 @@
         <module>admin-access-app</module>
         <module>angular-product-app</module>
         <module>database-service</module>
+        <module>rest-resources</module>
         <module>third-party</module>
         <module>third-party-cdi</module>
     </modules>
diff --git a/examples/demo-template/rest-resources/pom.xml b/examples/demo-template/rest-resources/pom.xml
new file mode 100755
index 0000000..d27b9c0
--- /dev/null
+++ b/examples/demo-template/rest-resources/pom.xml
@@ -0,0 +1,90 @@
+<?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.1.0.Final-SNAPSHOT</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.keycloak.example.demo</groupId>
+    <artifactId>rest-resources</artifactId>
+    <packaging>war</packaging>
+    <name>Rest Resources</name>
+    <description/>
+
+    <repositories>
+        <repository>
+            <id>jboss</id>
+            <name>jboss repo</name>
+            <url>http://repository.jboss.org/nexus/content/groups/public/</url>
+        </repository>
+    </repositories>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.servlet</groupId>
+            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-adapter-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>${keycloak.apache.httpcomponents.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>rest-resources</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </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>${maven.compiler.source}</source>
+                    <target>${maven.compiler.target}</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/examples/demo-template/rest-resources/src/main/java/org/keycloak/example/PublicResources.java b/examples/demo-template/rest-resources/src/main/java/org/keycloak/example/PublicResources.java
new file mode 100755
index 0000000..056f1d5
--- /dev/null
+++ b/examples/demo-template/rest-resources/src/main/java/org/keycloak/example/PublicResources.java
@@ -0,0 +1,36 @@
+package org.keycloak.example;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.spi.HttpRequest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Request;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+@Path("public")
+public class PublicResources {
+
+    @Context
+    HttpServletRequest request;
+
+    @POST
+    @Consumes("text/plain")
+    @Produces("text/plain")
+    @NoCache
+    public String get(String text) {
+        StringBuilder result = new StringBuilder();
+        Principal userPrincipal = request.getUserPrincipal();
+        if(userPrincipal != null){
+            result.append("Hello ").append(userPrincipal.getName()).append("\r\n");
+        }
+        result.append("You said: ").append(text);
+
+        return result.toString();
+    }
+}
diff --git a/examples/demo-template/rest-resources/src/main/java/org/keycloak/example/ResourceApplication.java b/examples/demo-template/rest-resources/src/main/java/org/keycloak/example/ResourceApplication.java
new file mode 100755
index 0000000..ab0040c
--- /dev/null
+++ b/examples/demo-template/rest-resources/src/main/java/org/keycloak/example/ResourceApplication.java
@@ -0,0 +1,9 @@
+package org.keycloak.example;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+@ApplicationPath("/")
+public class ResourceApplication extends Application
+{
+}
diff --git a/examples/demo-template/rest-resources/src/main/java/org/keycloak/example/SecretResources.java b/examples/demo-template/rest-resources/src/main/java/org/keycloak/example/SecretResources.java
new file mode 100755
index 0000000..ee5efa9
--- /dev/null
+++ b/examples/demo-template/rest-resources/src/main/java/org/keycloak/example/SecretResources.java
@@ -0,0 +1,33 @@
+package org.keycloak.example;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import java.security.Principal;
+
+@Path("secret")
+public class SecretResources {
+
+    @Context
+    HttpServletRequest request;
+
+    @POST
+    @Consumes("text/plain")
+    @Produces("text/plain")
+    @NoCache
+    public String get(String text) {
+        StringBuilder result = new StringBuilder();
+        Principal userPrincipal = request.getUserPrincipal();
+        if(userPrincipal != null){
+            result.append("Hello ").append(userPrincipal.getName()).append("\r\n");
+        }
+        result.append("You said: ").append(text);
+
+        return result.toString();
+    }
+}
diff --git a/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
new file mode 100755
index 0000000..9c1bac9
--- /dev/null
+++ b/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -0,0 +1,9 @@
+<jboss-deployment-structure>
+    <deployment>
+        <dependencies>
+            <!-- the Demo code uses classes in these modules.  These are optional to import if you are not using
+                 Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
+            <module name="org.apache.httpcomponents"/>
+        </dependencies>
+    </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/keycloak.json b/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/keycloak.json
new file mode 100755
index 0000000..caed050
--- /dev/null
+++ b/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,7 @@
+{
+    "realm" : "demo",
+    "resource" : "rest-resources",
+    "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "auth-server-url": "/auth",
+    "ssl-required" : "external"
+}
diff --git a/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/web.xml b/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..1c619b0
--- /dev/null
+++ b/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,43 @@
+<?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>rest-resources</module-name>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Public</web-resource-name>
+            <url-pattern>/public/*</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secure</web-resource-name>
+            <url-pattern>/secure/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <!--
+    <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> -->
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/web.xml.unconfigured b/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/web.xml.unconfigured
new file mode 100755
index 0000000..cce3b0b
--- /dev/null
+++ b/examples/demo-template/rest-resources/src/main/webapp/WEB-INF/web.xml.unconfigured
@@ -0,0 +1,47 @@
+<?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>rest-resources</module-name>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Public</web-resource-name>
+            <url-pattern>/public/*</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secure</web-resource-name>
+            <url-pattern>/secure/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+            <role-name>admin</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <!--
+    <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> -->
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/examples/demo-template/testrealm.json b/examples/demo-template/testrealm.json
index da92138..cc8e02f 100755
--- a/examples/demo-template/testrealm.json
+++ b/examples/demo-template/testrealm.json
@@ -148,6 +148,16 @@
             "adminUrl": "/database",
             "baseUrl": "/database",
             "bearerOnly": true
+        },
+        {
+            "name": "rest-resources",
+            "enabled": true,
+            "publicClient": true,
+            "adminUrl": "/rest-resources",
+            "baseUrl": "/rest-resources",
+            "redirectUris": [
+                "/rest-resources/*"
+            ]
         }
     ],
     "oauthClients": [
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
index bd853da..05a2773 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
@@ -76,6 +76,11 @@ public abstract class RequestAuthenticator {
             }
         }
 
+        if(!isAuthenticationRequired()){
+            log.debug("NOT_ATTEMPTED: authentication is not required");
+            return AuthOutcome.NOT_ATTEMPTED;
+        }
+
         if (log.isTraceEnabled()) {
             log.trace("try oauth");
         }
@@ -137,6 +142,7 @@ public abstract class RequestAuthenticator {
     protected abstract void completeOAuthAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal);
     protected abstract void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method);
     protected abstract String getHttpSessionId(boolean create);
+    protected abstract boolean isAuthenticationRequired();
 
     protected void completeAuthentication(BearerTokenRequestAuthenticator bearer, String method) {
         RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(deployment, null, bearer.getTokenString(), bearer.getToken(), null, null, null);
diff --git a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/JettyRequestAuthenticator.java b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/JettyRequestAuthenticator.java
index 0556b01..7e90aef 100755
--- a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/JettyRequestAuthenticator.java
+++ b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/JettyRequestAuthenticator.java
@@ -82,4 +82,9 @@ public class JettyRequestAuthenticator extends RequestAuthenticator {
     }
 
 
+    @Override
+    protected boolean isAuthenticationRequired() {
+        //TODO: find out if authentication is required
+        return true;
+    }
 }
diff --git a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java b/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java
index 58989ef..356c4a5 100755
--- a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java
+++ b/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java
@@ -90,4 +90,10 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
         HttpSession session = request.getSession(create);
         return session != null ? session.getId() : null;
     }
+
+    @Override
+    protected boolean isAuthenticationRequired() {
+        //TODO: find out if authentication is required
+        return true;
+    }
 }
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowKeycloakAuthMech.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowKeycloakAuthMech.java
index 1e49be9..9a35896 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowKeycloakAuthMech.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowKeycloakAuthMech.java
@@ -103,7 +103,6 @@ public abstract class AbstractUndertowKeycloakAuthMech implements Authentication
         if (outcome == AuthOutcome.FAILED) {
             return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
         }
-
         return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
     }
 
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowRequestAuthenticator.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowRequestAuthenticator.java
index f154ba3..26be637 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowRequestAuthenticator.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowRequestAuthenticator.java
@@ -87,4 +87,9 @@ public abstract class AbstractUndertowRequestAuthenticator extends RequestAuthen
      * @return The account
      */
     protected abstract KeycloakUndertowAccount createAccount(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal);
+
+    @Override
+    protected boolean isAuthenticationRequired() {
+        return securityContext.isAuthenticationRequired();
+    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/excluded/ExcludedResourceTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/excluded/ExcludedResourceTest.java
new file mode 100644
index 0000000..ffaaba7
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/excluded/ExcludedResourceTest.java
@@ -0,0 +1,192 @@
+package org.keycloak.testsuite.excluded;
+
+import io.undertow.servlet.api.*;
+import org.jboss.resteasy.spi.ResteasyDeployment;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.idm.*;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testutils.KeycloakServer;
+
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Arrays;
+import java.util.HashSet;
+
+/**
+ * Created by michigerber on 21.12.14.
+ */
+public class ExcludedResourceTest {
+
+    private static KeycloakServer server;
+
+    @BeforeClass
+    public static void before() throws Throwable {
+        server = new KeycloakServer();
+        server.start();
+        importRealm();
+        deployApp();
+    }
+
+    private static void importRealm() {
+        RealmRepresentation realm = new RealmRepresentation();
+        realm.setId("test");
+        realm.setRealm("test");
+        realm.setEnabled(true);
+        realm.setPrivateKey("MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=");
+        realm.setPublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB");
+        realm.setPasswordCredentialGrantAllowed(true);
+        realm.setRequiredCredentials(new HashSet<String>(Arrays.asList(CredentialRepresentation.PASSWORD)));
+
+        ApplicationRepresentation applicationRepresentation = new ApplicationRepresentation();
+        applicationRepresentation.setName("app");
+        applicationRepresentation.setBaseUrl("/app");
+        applicationRepresentation.setPublicClient(true);
+        applicationRepresentation.setEnabled(true);
+        applicationRepresentation.setRedirectUris(Arrays.asList("/app/*"));
+        realm.setApplications(Arrays.asList(applicationRepresentation));
+
+        UserRepresentation userRepresentation = new UserRepresentation();
+        userRepresentation.setId("user");
+        userRepresentation.setUsername("user");
+        userRepresentation.setEnabled(true);
+        CredentialRepresentation credential = new CredentialRepresentation();
+        credential.setType(CredentialRepresentation.PASSWORD);
+        credential.setValue("password");
+        userRepresentation.setCredentials(Arrays.asList(credential));
+        userRepresentation.setRealmRoles(Arrays.asList("user"));
+        realm.setUsers(Arrays.asList(userRepresentation));
+
+        RoleRepresentation roleRepresentation = new RoleRepresentation();
+        roleRepresentation.setName("user");
+        RolesRepresentation rolesRepresentation = new RolesRepresentation();
+        rolesRepresentation.setRealm(Arrays.asList(roleRepresentation));
+        realm.setRoles(rolesRepresentation);
+
+        server.importRealm(realm);
+    }
+
+    private static void deployApp() {
+
+        ResteasyDeployment resteasyDeployment = new ResteasyDeployment();
+        DeploymentInfo deploymentInfo = new DeploymentInfo();
+        deploymentInfo.setDeploymentName("app");
+        deploymentInfo.setContextPath("/app");
+        deploymentInfo.setClassLoader(ExcludedResourceTest.class.getClassLoader());
+
+        ServletInfo servletInfo = new ServletInfo("post", PostServlet.class);
+        servletInfo.addMappings("/public");
+        servletInfo.addMappings("/secure");
+        deploymentInfo.addServlet(servletInfo);
+
+
+        SecurityConstraint publicConstraint = new SecurityConstraint();
+        WebResourceCollection publicResource = new WebResourceCollection();
+        publicResource.addUrlPattern("/public/*");
+        publicConstraint.addWebResourceCollection(publicResource);
+        publicConstraint.setEmptyRoleSemantic(SecurityInfo.EmptyRoleSemantic.PERMIT);
+        deploymentInfo.addSecurityConstraint(publicConstraint);
+
+        SecurityConstraint secureConstraint = new SecurityConstraint();
+        WebResourceCollection secureResources = new WebResourceCollection();
+        secureResources.addUrlPattern("/*");
+        secureConstraint.addWebResourceCollection(secureResources);
+        secureConstraint.addRoleAllowed("user");
+        deploymentInfo.addSecurityConstraint(secureConstraint);
+        deploymentInfo.addSecurityRole("user");
+
+        deploymentInfo.setLoginConfig(new LoginConfig("KEYCLOAK", "test"));
+
+        deploymentInfo.addInitParameter("keycloak.config.file", ExcludedResourceTest.class.getResource("keycloak.json").getFile());
+
+        server.getServer().deploy(deploymentInfo);
+    }
+
+    @AfterClass
+    public static void after() {
+        server.stop();
+    }
+
+    @Test
+    public void testPublicWithoutToken() throws InterruptedException {
+        Response post = ClientBuilder.newClient()
+                .target("http://localhost:8081/app")
+                .path("public")
+                .request()
+                .post(Entity.entity("Hallo", MediaType.TEXT_PLAIN_TYPE));
+
+        String response = post.readEntity(String.class);
+        Assert.assertEquals("you said: Hallo", response);
+    }
+
+    @Test
+    public void testSecureWithoutToken() throws InterruptedException {
+        Response post = ClientBuilder.newClient()
+                .target("http://localhost:8081/app")
+                .path("secure")
+                .request()
+                .post(Entity.entity("Hallo", MediaType.TEXT_PLAIN_TYPE));
+
+        //Redirect to login
+        Assert.assertEquals(302, post.getStatusInfo().getStatusCode());
+    }
+    @Test
+    public void testSecureWithToken() throws InterruptedException, JSONException {
+        Form form = new Form();
+        form.param("username","user");
+        form.param("password","password");
+        form.param("client_id","app");
+
+        AccessTokenResponse token = ClientBuilder.newClient()
+                .target("http://localhost:8081/auth")
+                .path("/realms/test/tokens/grants/access")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.form(form))
+                .readEntity(AccessTokenResponse.class);
+
+        Response post = ClientBuilder.newClient()
+                .target("http://localhost:8081/app")
+                .path("secure")
+                .request()
+                .header("Authorization", "Bearer " + token.getToken())
+                .post(Entity.entity("Hallo", MediaType.TEXT_PLAIN_TYPE));
+
+        String response = post.readEntity(String.class);
+        Assert.assertEquals("Hello user, you said: Hallo", response);
+
+    }
+
+    @Test
+    public void testPublicWithToken() throws InterruptedException, JSONException {
+        Form form = new Form();
+        form.param("username","user");
+        form.param("password","password");
+        form.param("client_id","app");
+
+        AccessTokenResponse token = ClientBuilder.newClient()
+                .target("http://localhost:8081/auth")
+                .path("/realms/test/tokens/grants/access")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.form(form))
+                .readEntity(AccessTokenResponse.class);
+
+        Response post = ClientBuilder.newClient()
+                .target("http://localhost:8081/app")
+                .path("public")
+                .request()
+                .header("Authorization", "Bearer " + token.getToken())
+                .post(Entity.entity("Hallo", MediaType.TEXT_PLAIN_TYPE));
+
+        String response = post.readEntity(String.class);
+        Assert.assertEquals("Hello user, you said: Hallo", response);
+    }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/excluded/PostServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/excluded/PostServlet.java
new file mode 100644
index 0000000..9c9c41f
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/excluded/PostServlet.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.excluded;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Scanner;
+
+/**
+ * Created by michigerber on 21.12.14.
+ */
+public class PostServlet extends HttpServlet {
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        StringBuilder response = new StringBuilder();
+        if(req.getUserPrincipal() != null){
+            response.append("Hello "+req.getUserPrincipal().getName()).append(", ");
+        }
+        response.append("you said: ");
+        Scanner scanner = new Scanner(req.getInputStream());
+        while(scanner.hasNext()){
+            response.append(scanner.next());
+        }
+        resp.getWriter().write(response.toString());
+    }
+
+}
diff --git a/testsuite/integration/src/test/resources/org/keycloak/testsuite/excluded/keycloak.json b/testsuite/integration/src/test/resources/org/keycloak/testsuite/excluded/keycloak.json
new file mode 100755
index 0000000..9b5d568
--- /dev/null
+++ b/testsuite/integration/src/test/resources/org/keycloak/testsuite/excluded/keycloak.json
@@ -0,0 +1,7 @@
+{
+    "realm" : "test",
+    "resource" : "app",
+    "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "auth-server-url": "/auth",
+    "ssl-required" : "external"
+}