Merge pull request #899 from patriot1burke/master

RESTEASY-901
This commit is contained in:
Bill Burke 2014-12-22 16:06:52 -05:00
commit 358f968429
17 changed files with 11 additions and 517 deletions

View file

@ -34,7 +34,6 @@
<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>

View file

@ -1,90 +0,0 @@
<?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>

View file

@ -1,36 +0,0 @@
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();
}
}

View file

@ -1,9 +0,0 @@
package org.keycloak.example;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class ResourceApplication extends Application
{
}

View file

@ -1,33 +0,0 @@
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();
}
}

View file

@ -1,9 +0,0 @@
<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>

View file

@ -1,7 +0,0 @@
{
"realm" : "demo",
"resource" : "rest-resources",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "/auth",
"ssl-required" : "external"
}

View file

@ -1,43 +0,0 @@
<?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>

View file

@ -1,47 +0,0 @@
<?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>

View file

@ -153,6 +153,7 @@ public class OAuthRequestAuthenticator {
exchange.getResponse().setStatus(403);
return true;
}
tokenStore.saveRequest();
log.debug("Sending redirect to login page: " + redirect);
exchange.getResponse().setStatus(302);
exchange.getResponse().setCookie(deployment.getStateCookieName(), state, /* need to set path? */ null, null, -1, deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr()), false);
@ -202,7 +203,6 @@ public class OAuthRequestAuthenticator {
} else {
log.debug("redirecting to auth server");
challenge = loginRedirect();
tokenStore.saveRequest();
return AuthOutcome.NOT_ATTEMPTED;
}
} else {

View file

@ -76,11 +76,6 @@ 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");
}
@ -142,7 +137,6 @@ 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);

View file

@ -82,9 +82,4 @@ public class JettyRequestAuthenticator extends RequestAuthenticator {
}
@Override
protected boolean isAuthenticationRequired() {
//TODO: find out if authentication is required
return true;
}
}

View file

@ -91,9 +91,4 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
return session != null ? session.getId() : null;
}
@Override
protected boolean isAuthenticationRequired() {
//TODO: find out if authentication is required
return true;
}
}

View file

@ -88,8 +88,4 @@ public abstract class AbstractUndertowRequestAuthenticator extends RequestAuthen
*/
protected abstract KeycloakUndertowAccount createAccount(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal);
@Override
protected boolean isAuthenticationRequired() {
return securityContext.isAuthenticationRequired();
}
}

View file

@ -161,6 +161,16 @@ public class AdapterTestStrategy extends ExternalResource {
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
driver.navigate().to(APP_SERVER_BASE_URL + "/customer-portal");
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
// test unsecured POST KEYCLOAK-901
Client client = ClientBuilder.newClient();
Form form = new Form();
form.param("parameter", "hello");
String text = client.target(APP_SERVER_BASE_URL + "/input-portal/unsecured").request().post(Entity.form(form), String.class);
Assert.assertTrue(text.contains("parameter=hello"));
client.close();
}

View file

@ -1,192 +0,0 @@
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);
}
}

View file

@ -1,29 +0,0 @@
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());
}
}