keycloak-uncached
Changes
distribution/pom.xml 2(+2 -0)
examples/demo-template/admin-access-app/src/main/java/org/keycloak/example/AdminClient.java 2(+1 -1)
integration/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java 1(+1 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java 2(+1 -1)
integration/jaxrs-oauth-client/pom.xml 18(+13 -5)
integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsBearerTokenFilter.java 129(+14 -115)
integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsBearerTokenFilterImpl.java 289(+289 -0)
integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/OsgiJaxrsBearerTokenFilterImpl.java 78(+78 -0)
integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/AbstractKeycloakJettyAuthenticator.java 2(+1 -1)
integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java 2(+1 -1)
integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java 2(+1 -1)
integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java 2(+1 -1)
testsuite/integration/pom.xml 5(+5 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java 2(+1 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsTestApplication.java 38(+38 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java 27(+27 -0)
testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak-resource-mappings.json 10(+10 -0)
Details
diff --git a/core/src/main/java/org/keycloak/constants/GenericConstants.java b/core/src/main/java/org/keycloak/constants/GenericConstants.java
new file mode 100644
index 0000000..a5a8f83
--- /dev/null
+++ b/core/src/main/java/org/keycloak/constants/GenericConstants.java
@@ -0,0 +1,10 @@
+package org.keycloak.constants;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class GenericConstants {
+
+ public static final String PROTOCOL_CLASSPATH = "classpath:";
+
+}
diff --git a/core/src/main/java/org/keycloak/util/KeystoreUtil.java b/core/src/main/java/org/keycloak/util/KeystoreUtil.java
index 6c715a2..ba264c0 100755
--- a/core/src/main/java/org/keycloak/util/KeystoreUtil.java
+++ b/core/src/main/java/org/keycloak/util/KeystoreUtil.java
@@ -5,18 +5,18 @@ import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
+import org.keycloak.constants.GenericConstants;
+
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeystoreUtil {
- private static final String PROTOCOL_CLASSPATH = "classpath:";
-
public static KeyStore loadKeyStore(String filename, String password) throws Exception {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
- InputStream trustStream = (filename.startsWith(PROTOCOL_CLASSPATH))
- ?KeystoreUtil.class.getResourceAsStream(filename.replace(PROTOCOL_CLASSPATH, ""))
+ InputStream trustStream = (filename.startsWith(GenericConstants.PROTOCOL_CLASSPATH))
+ ?KeystoreUtil.class.getResourceAsStream(filename.replace(GenericConstants.PROTOCOL_CLASSPATH, ""))
:new FileInputStream(new File(filename));
trustStore.load(trustStream, password.toCharArray());
trustStream.close();
distribution/pom.xml 2(+2 -0)
diff --git a/distribution/pom.xml b/distribution/pom.xml
index 973bc6e..332b270 100755
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -30,6 +30,8 @@
<module>tomcat7-adapter-zip</module>
<module>eap6-adapter-zip</module>
<module>wildfly-adapter-zip</module>
+ <module>jetty91-adapter-zip</module>
+ <module>jetty92-adapter-zip</module>
<module>examples-docs-zip</module>
<module>theme-template-zip</module>
<module>war-zip</module>
diff --git a/examples/demo-template/admin-access-app/src/main/java/org/keycloak/example/AdminClient.java b/examples/demo-template/admin-access-app/src/main/java/org/keycloak/example/AdminClient.java
index caa9ed6..9f7ec37 100755
--- a/examples/demo-template/admin-access-app/src/main/java/org/keycloak/example/AdminClient.java
+++ b/examples/demo-template/admin-access-app/src/main/java/org/keycloak/example/AdminClient.java
@@ -9,7 +9,7 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.keycloak.OAuth2Constants;
-import org.keycloak.ServiceUrlConstants;
+import org.keycloak.constants.ServiceUrlConstants;
import org.keycloak.adapters.HttpClientBuilder;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.idm.RoleRepresentation;
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
index f04f144..fcbf1fe 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
@@ -2,6 +2,7 @@ package org.keycloak.adapters;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.representations.AccessToken;
import java.io.IOException;
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java
index 8a35572..31bbe0a 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java
@@ -6,6 +6,7 @@ import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.RSATokenVerifier;
import org.keycloak.VerificationException;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.IDToken;
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
index fdd295e..4b13bd8 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
@@ -2,7 +2,7 @@ package org.keycloak.adapters;
import org.apache.http.client.HttpClient;
import org.jboss.logging.Logger;
-import org.keycloak.ServiceUrlConstants;
+import org.keycloak.constants.ServiceUrlConstants;
import org.keycloak.enums.RelativeUrlsUsed;
import org.keycloak.enums.SslRequired;
import org.keycloak.enums.TokenStore;
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java
index 099697f..aff38dc 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java
@@ -2,6 +2,7 @@ package org.keycloak.adapters;
import org.jboss.logging.Logger;
import org.keycloak.Version;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.representations.adapters.action.AdminAction;
@@ -166,7 +167,7 @@ public class PreAuthActionsHandler {
if (!facade.getRequest().isSecure() && deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr())) {
log.warn("SSL is required for adapter admin action");
facade.getResponse().sendError(403, "ssl required");
-
+ return null;
}
String token = StreamUtil.readString(facade.getRequest().getInputStream());
if (token == null) {
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
index f4a3142..741edc7 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
@@ -8,6 +8,7 @@ import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.keycloak.OAuth2Constants;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.util.BasicAuthHelper;
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
index e63d43d..c2d42c1 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
@@ -13,7 +13,7 @@ import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakSecurityContext;
-import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.AuthChallenge;
integration/jaxrs-oauth-client/pom.xml 18(+13 -5)
diff --git a/integration/jaxrs-oauth-client/pom.xml b/integration/jaxrs-oauth-client/pom.xml
index ef9bc1b..a167f99 100755
--- a/integration/jaxrs-oauth-client/pom.xml
+++ b/integration/jaxrs-oauth-client/pom.xml
@@ -15,11 +15,6 @@
<dependencies>
<dependency>
- <groupId>org.jboss.logging</groupId>
- <artifactId>jboss-logging</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>jaxrs-api</artifactId>
<version>${resteasy.version.latest}</version>
@@ -44,6 +39,12 @@
<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.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<scope>provided</scope>
@@ -69,6 +70,13 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.0</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsBearerTokenFilter.java b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsBearerTokenFilter.java
old mode 100755
new mode 100644
index e7ffc5b..f0bce71
--- a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsBearerTokenFilter.java
+++ b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsBearerTokenFilter.java
@@ -1,115 +1,14 @@
-package org.keycloak.jaxrs;
-
-import org.jboss.logging.Logger;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
-import org.keycloak.KeycloakPrincipal;
-import org.keycloak.KeycloakSecurityContext;
-import org.keycloak.RSATokenVerifier;
-import org.keycloak.VerificationException;
-import org.keycloak.representations.AccessToken;
-
-import javax.annotation.Priority;
-import javax.ws.rs.Priorities;
-import javax.ws.rs.container.ContainerRequestContext;
-import javax.ws.rs.container.ContainerRequestFilter;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.SecurityContext;
-import java.io.IOException;
-import java.security.Principal;
-import java.security.PublicKey;
-
-/**
- * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
- * @version $Revision: 1 $
- */
-@Priority(Priorities.AUTHENTICATION)
-public class JaxrsBearerTokenFilter implements ContainerRequestFilter {
- private static Logger log = Logger.getLogger(JaxrsBearerTokenFilter.class);
- protected String realm;
- protected PublicKey realmPublicKey;
- protected String resourceName;
-
- public JaxrsBearerTokenFilter(String realm, PublicKey realmPublicKey, String resourceName) {
- this.realm = realm;
- this.realmPublicKey = realmPublicKey;
- this.resourceName = resourceName;
- }
-
- protected void challengeResponse(ContainerRequestContext request, String error, String description) {
- StringBuilder header = new StringBuilder("Bearer realm=\"");
- header.append(realm).append("\"");
- if (error != null) {
- header.append(", error=\"").append(error).append("\"");
- }
- if (description != null) {
- header.append(", error_description=\"").append(description).append("\"");
- }
- request.abortWith(Response.status(Response.Status.UNAUTHORIZED).header(HttpHeaders.WWW_AUTHENTICATE, header.toString()).build());
- return;
- }
-
- @Context
- protected SecurityContext securityContext;
-
- @Override
- public void filter(ContainerRequestContext request) throws IOException {
- String authHeader = request.getHeaderString(HttpHeaders.AUTHORIZATION);
- if (authHeader == null) {
- challengeResponse(request, null, null);
- return;
- }
-
- String[] split = authHeader.trim().split("\\s+");
- if (split == null || split.length != 2) challengeResponse(request, null, null);
- if (!split[0].equalsIgnoreCase("Bearer")) challengeResponse(request, null, null);
-
-
- String tokenString = split[1];
-
-
- try {
- AccessToken token = RSATokenVerifier.verifyToken(tokenString, realmPublicKey, realm);
- KeycloakSecurityContext skSession = new KeycloakSecurityContext(tokenString, token, null, null);
- ResteasyProviderFactory.pushContext(KeycloakSecurityContext.class, skSession);
-
- final KeycloakPrincipal<KeycloakSecurityContext> principal = new KeycloakPrincipal<KeycloakSecurityContext>(token.getSubject(), skSession);
- final boolean isSecure = securityContext.isSecure();
- final AccessToken.Access access;
- if (resourceName != null) {
- access = token.getResourceAccess(resourceName);
- } else {
- access = token.getRealmAccess();
- }
- SecurityContext ctx = new SecurityContext() {
- @Override
- public Principal getUserPrincipal() {
- return principal;
- }
-
- @Override
- public boolean isUserInRole(String role) {
- if (access == null) return false;
- if (access.getRoles() == null) return false;
- return access.getRoles().contains(role);
- }
-
- @Override
- public boolean isSecure() {
- return isSecure;
- }
-
- @Override
- public String getAuthenticationScheme() {
- return "OAUTH_BEARER";
- }
- };
- request.setSecurityContext(ctx);
- } catch (VerificationException e) {
- log.error("Failed to verify token", e);
- challengeResponse(request, "invalid_token", e.getMessage());
- }
- }
-
-}
+package org.keycloak.jaxrs;
+
+import javax.annotation.Priority;
+import javax.ws.rs.Priorities;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.PreMatching;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@PreMatching
+@Priority(Priorities.AUTHENTICATION)
+public interface JaxrsBearerTokenFilter extends ContainerRequestFilter {
+}
diff --git a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsBearerTokenFilterImpl.java b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsBearerTokenFilterImpl.java
new file mode 100755
index 0000000..33795c2
--- /dev/null
+++ b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsBearerTokenFilterImpl.java
@@ -0,0 +1,289 @@
+package org.keycloak.jaxrs;
+
+import org.keycloak.KeycloakPrincipal;
+import org.keycloak.adapters.AdapterDeploymentContext;
+import org.keycloak.adapters.AdapterUtils;
+import org.keycloak.adapters.AuthChallenge;
+import org.keycloak.adapters.AuthOutcome;
+import org.keycloak.adapters.AuthenticatedActionsHandler;
+import org.keycloak.adapters.BearerTokenRequestAuthenticator;
+import org.keycloak.adapters.KeycloakConfigResolver;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.KeycloakDeploymentBuilder;
+import org.keycloak.adapters.NodesRegistrationManagement;
+import org.keycloak.adapters.PreAuthActionsHandler;
+import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
+import org.keycloak.adapters.UserSessionManagement;
+import org.keycloak.constants.GenericConstants;
+
+import javax.annotation.Priority;
+import javax.ws.rs.Priorities;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.PreMatching;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Principal;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@PreMatching
+@Priority(Priorities.AUTHENTICATION)
+public class JaxrsBearerTokenFilterImpl implements JaxrsBearerTokenFilter {
+
+ private final static Logger log = Logger.getLogger("" + JaxrsBearerTokenFilterImpl.class);
+
+ private String keycloakConfigFile;
+ private String keycloakConfigResolverClass;
+ protected volatile boolean started;
+
+ protected AdapterDeploymentContext deploymentContext;
+
+ // TODO: Should also somehow handle stop lifecycle for de-registration
+ protected NodesRegistrationManagement nodesRegistrationManagement;
+ protected UserSessionManagement userSessionManagement = new EmptyUserSessionManagement();
+
+ public void setKeycloakConfigFile(String configFile) {
+ this.keycloakConfigFile = configFile;
+ attemptStart();
+ }
+
+ public String getKeycloakConfigFile() {
+ return this.keycloakConfigFile;
+ }
+
+ public String getKeycloakConfigResolverClass() {
+ return keycloakConfigResolverClass;
+ }
+
+ public void setKeycloakConfigResolverClass(String keycloakConfigResolverClass) {
+ this.keycloakConfigResolverClass = keycloakConfigResolverClass;
+ attemptStart();
+ }
+
+ // INITIALIZATION AND STARTUP
+
+ protected void attemptStart() {
+ if (started) {
+ throw new IllegalStateException("Filter already started. Make sure to specify just keycloakConfigResolver or keycloakConfigFile but not both");
+ }
+
+ if (isInitialized()) {
+ start();
+ } else {
+ log.fine("Not yet initialized");
+ }
+ }
+
+ protected boolean isInitialized() {
+ return this.keycloakConfigFile != null || this.keycloakConfigResolverClass != null;
+ }
+
+ protected void start() {
+ if (started) {
+ throw new IllegalStateException("Filter already started. Make sure to specify just keycloakConfigResolver or keycloakConfigFile but not both");
+ }
+
+ if (keycloakConfigResolverClass != null) {
+ Class<? extends KeycloakConfigResolver> resolverClass = loadResolverClass();
+
+ try {
+ KeycloakConfigResolver resolver = resolverClass.newInstance();
+ log.info("Using " + resolver + " to resolve Keycloak configuration on a per-request basis.");
+ this.deploymentContext = new AdapterDeploymentContext(resolver);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to instantiate resolver " + resolverClass);
+ }
+ } else {
+ if (keycloakConfigFile == null) {
+ throw new IllegalArgumentException("You need to specify either keycloakConfigResolverClass or keycloakConfigFile in configuration");
+ }
+ InputStream is = loadKeycloakConfigFile();
+ KeycloakDeployment kd = KeycloakDeploymentBuilder.build(is);
+ deploymentContext = new AdapterDeploymentContext(kd);
+ log.info("Keycloak is using a per-deployment configuration loaded from: " + keycloakConfigFile);
+ }
+
+ nodesRegistrationManagement = new NodesRegistrationManagement();
+ started = true;
+ }
+
+ protected Class<? extends KeycloakConfigResolver> loadResolverClass() {
+ try {
+ return (Class<? extends KeycloakConfigResolver>)getClass().getClassLoader().loadClass(keycloakConfigResolverClass);
+ } catch (ClassNotFoundException cnfe) {
+ // Fallback to tccl
+ try {
+ return (Class<? extends KeycloakConfigResolver>)Thread.currentThread().getContextClassLoader().loadClass(keycloakConfigResolverClass);
+ } catch (ClassNotFoundException cnfe2) {
+ throw new RuntimeException("Unable to find resolver class: " + keycloakConfigResolverClass);
+ }
+ }
+ }
+
+ protected InputStream loadKeycloakConfigFile() {
+ if (keycloakConfigFile.startsWith(GenericConstants.PROTOCOL_CLASSPATH)) {
+ String classPathLocation = keycloakConfigFile.replace(GenericConstants.PROTOCOL_CLASSPATH, "");
+ log.fine("Loading config from classpath on location: " + classPathLocation);
+ // Try current class classloader first
+ InputStream is = getClass().getClassLoader().getResourceAsStream(classPathLocation);
+ if (is == null) {
+ is = Thread.currentThread().getContextClassLoader().getResourceAsStream(classPathLocation);
+ }
+
+ if (is != null) {
+ return is;
+ } else {
+ throw new RuntimeException("Unable to find config from classpath: " + keycloakConfigFile);
+ }
+ } else {
+ // Fallback to file
+ try {
+ log.fine("Loading config from file: " + keycloakConfigFile);
+ return new FileInputStream(keycloakConfigFile);
+ } catch (FileNotFoundException fnfe) {
+ log.severe("Config not found on " + keycloakConfigFile);
+ throw new RuntimeException(fnfe);
+ }
+ }
+ }
+
+ // REQUEST HANDLING
+
+ @Override
+ public void filter(ContainerRequestContext request) throws IOException {
+ SecurityContext securityContext = getRequestSecurityContext(request);
+ JaxrsHttpFacade facade = new JaxrsHttpFacade(request, securityContext);
+ if (handlePreauth(facade)) {
+ return;
+ }
+
+ KeycloakDeployment resolvedDeployment = deploymentContext.resolveDeployment(facade);
+
+ nodesRegistrationManagement.tryRegister(resolvedDeployment);
+
+ bearerAuthentication(facade, request, resolvedDeployment);
+ }
+
+ protected boolean handlePreauth(JaxrsHttpFacade facade) {
+ PreAuthActionsHandler handler = new PreAuthActionsHandler(userSessionManagement, deploymentContext, facade);
+ if (handler.handleRequest()) {
+ // Send response now (if not already sent)
+ if (!facade.isResponseFinished()) {
+ facade.getResponse().end();
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ protected void bearerAuthentication(JaxrsHttpFacade facade, ContainerRequestContext request, KeycloakDeployment resolvedDeployment) {
+ BearerTokenRequestAuthenticator bearer = new BearerTokenRequestAuthenticator(resolvedDeployment);
+ AuthOutcome outcome = bearer.authenticate(facade);
+ if (outcome == AuthOutcome.FAILED || outcome == AuthOutcome.NOT_ATTEMPTED) {
+ AuthChallenge challenge = bearer.getChallenge();
+ log.fine("Authentication outcome: " + outcome);
+ boolean challengeSent = challenge.challenge(facade);
+ if (!challengeSent) {
+ // Use some default status code
+ facade.getResponse().setStatus(Response.Status.UNAUTHORIZED.getStatusCode());
+ }
+
+ // Send response now (if not already sent)
+ if (!facade.isResponseFinished()) {
+ facade.getResponse().end();
+ }
+ return;
+ } else {
+ if (verifySslFailed(facade, resolvedDeployment)) {
+ return;
+ }
+ }
+
+ propagateSecurityContext(facade, request, resolvedDeployment, bearer);
+ handleAuthActions(facade, resolvedDeployment);
+ }
+
+ protected void propagateSecurityContext(JaxrsHttpFacade facade, ContainerRequestContext request, KeycloakDeployment resolvedDeployment, BearerTokenRequestAuthenticator bearer) {
+ RefreshableKeycloakSecurityContext skSession = new RefreshableKeycloakSecurityContext(resolvedDeployment, null, bearer.getTokenString(), bearer.getToken(), null, null, null);
+
+ // Not needed to do resteasy specifics as KeycloakSecurityContext can be always retrieved from SecurityContext by typecast SecurityContext.getUserPrincipal to KeycloakPrincipal
+ // ResteasyProviderFactory.pushContext(KeycloakSecurityContext.class, skSession);
+
+ facade.setSecurityContext(skSession);
+ String principalName = AdapterUtils.getPrincipalName(resolvedDeployment, bearer.getToken());
+ final KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = new KeycloakPrincipal<RefreshableKeycloakSecurityContext>(principalName, skSession);
+ SecurityContext anonymousSecurityContext = getRequestSecurityContext(request);
+ final boolean isSecure = anonymousSecurityContext.isSecure();
+ final Set<String> roles = AdapterUtils.getRolesFromSecurityContext(skSession);
+
+ SecurityContext ctx = new SecurityContext() {
+ @Override
+ public Principal getUserPrincipal() {
+ return principal;
+ }
+
+ @Override
+ public boolean isUserInRole(String role) {
+ return roles.contains(role);
+ }
+
+ @Override
+ public boolean isSecure() {
+ return isSecure;
+ }
+
+ @Override
+ public String getAuthenticationScheme() {
+ return "OAUTH_BEARER";
+ }
+ };
+ request.setSecurityContext(ctx);
+ }
+
+ protected boolean verifySslFailed(JaxrsHttpFacade facade, KeycloakDeployment deployment) {
+ if (!facade.getRequest().isSecure() && deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr())) {
+ log.warning("SSL is required to authenticate, but request is not secured");
+ facade.getResponse().sendError(403, "SSL required!");
+ return true;
+ }
+ return false;
+ }
+
+ protected SecurityContext getRequestSecurityContext(ContainerRequestContext request) {
+ return request.getSecurityContext();
+ }
+
+ protected void handleAuthActions(JaxrsHttpFacade facade, KeycloakDeployment deployment) {
+ AuthenticatedActionsHandler authActionsHandler = new AuthenticatedActionsHandler(deployment, facade);
+ if (authActionsHandler.handledRequest()) {
+ // Send response now (if not already sent)
+ if (!facade.isResponseFinished()) {
+ facade.getResponse().end();
+ }
+ }
+ }
+
+ // We don't have any sessions to manage with pure jaxrs filter
+ private static class EmptyUserSessionManagement implements UserSessionManagement {
+
+ @Override
+ public void logoutAll() {
+ }
+
+ @Override
+ public void logoutHttpSessions(List<String> ids) {
+ }
+ }
+
+}
diff --git a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsHttpFacade.java b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsHttpFacade.java
new file mode 100644
index 0000000..f29935d
--- /dev/null
+++ b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsHttpFacade.java
@@ -0,0 +1,172 @@
+package org.keycloak.jaxrs;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.cert.X509Certificate;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.SecurityContext;
+
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.HttpFacade;
+import org.keycloak.util.HostUtils;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class JaxrsHttpFacade implements HttpFacade {
+
+ protected final ContainerRequestContext requestContext;
+ protected final SecurityContext securityContext;
+ protected final RequestFacade requestFacade = new RequestFacade();
+ protected final ResponseFacade responseFacade = new ResponseFacade();
+ protected KeycloakSecurityContext keycloakSecurityContext;
+ protected boolean responseFinished;
+
+ public JaxrsHttpFacade(ContainerRequestContext containerRequestContext, SecurityContext securityContext) {
+ this.requestContext = containerRequestContext;
+ this.securityContext = securityContext;
+ }
+
+ protected class RequestFacade implements HttpFacade.Request {
+
+ @Override
+ public String getMethod() {
+ return requestContext.getMethod();
+ }
+
+ @Override
+ public String getURI() {
+ return requestContext.getUriInfo().getRequestUri().toString();
+ }
+
+ @Override
+ public boolean isSecure() {
+ return securityContext.isSecure();
+ }
+
+ @Override
+ public String getQueryParamValue(String param) {
+ MultivaluedMap<String, String> queryParams = requestContext.getUriInfo().getQueryParameters();
+ if (queryParams == null)
+ return null;
+ return queryParams.getFirst(param);
+ }
+
+ @Override
+ public Cookie getCookie(String cookieName) {
+ Map<String, javax.ws.rs.core.Cookie> cookies = requestContext.getCookies();
+ if (cookies == null)
+ return null;
+ javax.ws.rs.core.Cookie cookie = cookies.get(cookieName);
+ if (cookie == null)
+ return null;
+ return new Cookie(cookie.getName(), cookie.getValue(), cookie.getVersion(), cookie.getDomain(), cookie.getPath());
+ }
+
+ @Override
+ public String getHeader(String name) {
+ return requestContext.getHeaderString(name);
+ }
+
+ @Override
+ public List<String> getHeaders(String name) {
+ MultivaluedMap<String, String> headers = requestContext.getHeaders();
+ return (headers == null) ? null : headers.get(name);
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ return requestContext.getEntityStream();
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ // TODO: implement properly
+ return HostUtils.getIpAddress();
+ }
+ }
+
+ protected class ResponseFacade implements HttpFacade.Response {
+
+ private javax.ws.rs.core.Response.ResponseBuilder responseBuilder = javax.ws.rs.core.Response.status(204);
+
+ @Override
+ public void setStatus(int status) {
+ responseBuilder.status(status);
+ }
+
+ @Override
+ public void addHeader(String name, String value) {
+ responseBuilder.header(name, value);
+ }
+
+ @Override
+ public void setHeader(String name, String value) {
+ responseBuilder.header(name, value);
+ }
+
+ @Override
+ public void resetCookie(String name, String path) {
+ // For now doesn't need to be supported
+ throw new IllegalStateException("Not supported yet");
+ }
+
+ @Override
+ public void setCookie(String name, String value, String path, String domain, int maxAge, boolean secure, boolean httpOnly) {
+ // For now doesn't need to be supported
+ throw new IllegalStateException("Not supported yet");
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ // For now doesn't need to be supported
+ throw new IllegalStateException("Not supported yet");
+ }
+
+ @Override
+ public void sendError(int code, String message) {
+ javax.ws.rs.core.Response response = responseBuilder.status(code).entity(message).build();
+ requestContext.abortWith(response);
+ responseFinished = true;
+ }
+
+ @Override
+ public void end() {
+ javax.ws.rs.core.Response response = responseBuilder.build();
+ requestContext.abortWith(response);
+ responseFinished = true;
+ }
+ }
+
+ @Override
+ public KeycloakSecurityContext getSecurityContext() {
+ return keycloakSecurityContext;
+ }
+
+ public void setSecurityContext(KeycloakSecurityContext securityContext) {
+ this.keycloakSecurityContext = securityContext;
+ }
+
+ @Override
+ public Request getRequest() {
+ return requestFacade;
+ }
+
+ @Override
+ public Response getResponse() {
+ return responseFacade;
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain() {
+ throw new IllegalStateException("Not supported yet");
+ }
+
+ public boolean isResponseFinished() {
+ return responseFinished;
+ }
+}
diff --git a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
index b453203..6944782 100755
--- a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
+++ b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
@@ -1,6 +1,5 @@
package org.keycloak.jaxrs;
-import org.jboss.logging.Logger;
import org.keycloak.AbstractOAuthClient;
import org.keycloak.OAuth2Constants;
import org.keycloak.representations.AccessTokenResponse;
@@ -18,6 +17,7 @@ import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.util.Map;
+import java.util.logging.Logger;
/**
* Helper code to obtain oauth access tokens via browser redirects
@@ -26,7 +26,7 @@ import java.util.Map;
* @version $Revision: 1 $
*/
public class JaxrsOAuthClient extends AbstractOAuthClient {
- protected static final Logger logger = Logger.getLogger(JaxrsOAuthClient.class);
+ private final static Logger logger = Logger.getLogger("" + JaxrsOAuthClient.class);
protected Client client;
/**
@@ -80,8 +80,8 @@ public class JaxrsOAuthClient extends AbstractOAuthClient {
URI url = uriBuilder.build();
NewCookie cookie = new NewCookie(getStateCookieName(), state, getStateCookiePath(uriInfo), null, null, -1, isSecure, true);
- logger.debug("NewCookie: " + cookie.toString());
- logger.debug("Oauth Redirect to: " + url);
+ logger.fine("NewCookie: " + cookie.toString());
+ logger.fine("Oauth Redirect to: " + url);
return Response.status(302)
.location(url)
.cookie(cookie).build();
diff --git a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/OsgiJaxrsBearerTokenFilterImpl.java b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/OsgiJaxrsBearerTokenFilterImpl.java
new file mode 100644
index 0000000..2c2f4b0
--- /dev/null
+++ b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/OsgiJaxrsBearerTokenFilterImpl.java
@@ -0,0 +1,78 @@
+package org.keycloak.jaxrs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.logging.Logger;
+
+import javax.annotation.Priority;
+import javax.ws.rs.Priorities;
+import javax.ws.rs.container.PreMatching;
+
+import org.keycloak.adapters.KeycloakConfigResolver;
+import org.keycloak.constants.GenericConstants;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Variant of JaxrsBearerTokenFilter, which can be used to properly use resources from current osgi bundle
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@PreMatching
+@Priority(Priorities.AUTHENTICATION)
+public class OsgiJaxrsBearerTokenFilterImpl extends JaxrsBearerTokenFilterImpl {
+
+ private final static Logger log = Logger.getLogger("" + JaxrsBearerTokenFilterImpl.class);
+
+ private BundleContext bundleContext;
+
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ attemptStart();
+ }
+
+ @Override
+ protected boolean isInitialized() {
+ return super.isInitialized() && bundleContext != null;
+ }
+
+ @Override
+ protected Class<? extends KeycloakConfigResolver> loadResolverClass() {
+ String resolverClass = getKeycloakConfigResolverClass();
+ try {
+ return (Class<? extends KeycloakConfigResolver>) bundleContext.getBundle().loadClass(resolverClass);
+ } catch (ClassNotFoundException cnfe) {
+ log.warning("Not able to find class from bundleContext. Fallback to current classloader");
+ return super.loadResolverClass();
+ }
+ }
+
+ @Override
+ protected InputStream loadKeycloakConfigFile() {
+ String keycloakConfigFile = getKeycloakConfigFile();
+ if (keycloakConfigFile.startsWith(GenericConstants.PROTOCOL_CLASSPATH)) {
+
+ // Load from classpath of current bundle
+ String classPathLocation = keycloakConfigFile.replace(GenericConstants.PROTOCOL_CLASSPATH, "");
+ log.fine("Loading config from classpath on location: " + classPathLocation);
+
+ URL cfgUrl = bundleContext.getBundle().getResource(classPathLocation);
+ if (cfgUrl == null) {
+ log.warning("Not able to find configFile from bundleContext. Fallback to current classloader");
+ return super.loadKeycloakConfigFile();
+ }
+
+ try {
+ return cfgUrl.openStream();
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ } else {
+ return super.loadKeycloakConfigFile();
+ }
+ }
+}
diff --git a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/AbstractKeycloakJettyAuthenticator.java b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/AbstractKeycloakJettyAuthenticator.java
index e2e2cba..72f0d0f 100755
--- a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/AbstractKeycloakJettyAuthenticator.java
+++ b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/AbstractKeycloakJettyAuthenticator.java
@@ -12,7 +12,6 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
-import org.keycloak.adapters.AdapterConstants;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.AdapterUtils;
@@ -26,6 +25,7 @@ import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.NodesRegistrationManagement;
import org.keycloak.adapters.PreAuthActionsHandler;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.enums.TokenStore;
import org.keycloak.representations.adapters.config.AdapterConfig;
diff --git a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java
index e9013fd..5620636 100755
--- a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java
+++ b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java
@@ -1,7 +1,7 @@
package org.keycloak.servlet;
import org.apache.http.client.HttpClient;
-import org.keycloak.ServiceUrlConstants;
+import org.keycloak.constants.ServiceUrlConstants;
import org.keycloak.adapters.HttpClientBuilder;
import org.keycloak.enums.RelativeUrlsUsed;
import org.keycloak.representations.adapters.config.AdapterConfig;
diff --git a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java
index d62e9b0..5d0f271 100755
--- a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java
+++ b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java
@@ -12,7 +12,7 @@ import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig;
import org.keycloak.KeycloakSecurityContext;
-import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.AuthChallenge;
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
index 9484021..4014a92 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
@@ -32,7 +32,7 @@ import io.undertow.servlet.api.LoginConfig;
import io.undertow.servlet.api.ServletSessionConfig;
import io.undertow.servlet.util.ImmediateInstanceHandle;
import org.jboss.logging.Logger;
-import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
index 0c60ccb..2c47adb 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
@@ -14,7 +14,7 @@ import org.keycloak.Config;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
import org.keycloak.RSATokenVerifier;
-import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder;
@@ -41,7 +41,6 @@ import org.keycloak.services.resources.Cors;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.Urls;
-import org.keycloak.util.Base64Url;
import org.keycloak.util.BasicAuthHelper;
import org.keycloak.util.StreamUtil;
import org.keycloak.util.UriUtils;
diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
index 7760e52..d3fb82a 100755
--- a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
@@ -6,7 +6,7 @@ import org.jboss.resteasy.client.ClientRequest;
import org.jboss.resteasy.client.ClientResponse;
import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
import org.keycloak.TokenIdGenerator;
-import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
diff --git a/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java b/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java
index 0ce2793..0fdbc81 100755
--- a/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java
+++ b/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java
@@ -1,6 +1,5 @@
package org.keycloak.services.resources;
-import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@@ -22,7 +21,7 @@ import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.UnauthorizedException;
import org.keycloak.ClientConnection;
import org.keycloak.OAuth2Constants;
-import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder;
testsuite/integration/pom.xml 5(+5 -0)
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 77252b9..6ca12ba 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -126,6 +126,11 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
+ <artifactId>keycloak-jaxrs-oauth-client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
<artifactId>federation-properties-example</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
index e17208d..58d0851 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
@@ -28,7 +28,7 @@ import org.junit.Test;
import org.keycloak.Config;
import org.keycloak.OAuth2Constants;
import org.keycloak.Version;
-import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
index 24b04c9..8218258 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
@@ -8,7 +8,7 @@ import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
-import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.OpenIDConnectService;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/Constants.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/Constants.java
index 459f44c..3f009ef 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/Constants.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/Constants.java
@@ -26,6 +26,7 @@ package org.keycloak.testsuite;
*/
public class Constants {
- public static String AUTH_SERVER_ROOT = "http://localhost:8081/auth";
+ public static String SERVER_ROOT = "http://localhost:8081";
+ public static String AUTH_SERVER_ROOT = SERVER_ROOT + "/auth";
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsFilterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsFilterTest.java
new file mode 100644
index 0000000..936792d
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsFilterTest.java
@@ -0,0 +1,345 @@
+package org.keycloak.testsuite.jaxrs;
+
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExternalResource;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.TokenIdGenerator;
+import org.keycloak.adapters.CorsHeaders;
+import org.keycloak.constants.AdapterConstants;
+import org.keycloak.adapters.HttpClientBuilder;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.representations.adapters.action.PushNotBeforeAction;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.Constants;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.keycloak.util.Time;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class JaxrsFilterTest {
+
+ private static final String JAXRS_APP_URL = Constants.SERVER_ROOT + "/jaxrs-simple/res";
+ private static final String JAXRS_APP_PUSN_NOT_BEFORE_URL = Constants.SERVER_ROOT + "/jaxrs-simple/" + AdapterConstants.K_PUSH_NOT_BEFORE;
+
+ public static final String CONFIG_FILE_INIT_PARAM = "config-file";
+
+ @ClassRule
+ public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
+
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ ApplicationModel app = appRealm.addApplication("jaxrs-app");
+ app.setEnabled(true);
+ RoleModel role = app.addRole("jaxrs-app-user");
+ UserModel user = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm);
+ user.grantRole(role);
+
+ JaxrsFilterTest.appRealm = appRealm;
+ }
+ });
+
+ @ClassRule
+ public static ExternalResource clientRule = new ExternalResource() {
+
+ @Override
+ protected void before() throws Throwable {
+ DefaultHttpClient httpClient = (DefaultHttpClient) new HttpClientBuilder().build();
+ ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
+ client = new ResteasyClientBuilder().httpEngine(engine).build();
+ }
+
+ @Override
+ protected void after() {
+ client.close();
+ }
+ };
+
+ private static ResteasyClient client;
+
+ @Rule
+ public WebRule webRule = new WebRule(this);
+
+ @WebResource
+ protected WebDriver driver;
+
+ // Used for signing admin action
+ protected static RealmModel appRealm;
+
+
+ @Test
+ public void testBasic() {
+ keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ Map<String,String> initParams = new TreeMap<String,String>();
+ initParams.put(CONFIG_FILE_INIT_PARAM, "classpath:jaxrs-test/jaxrs-keycloak.json");
+ keycloakRule.deployJaxrsApplication("JaxrsSimpleApp", "/jaxrs-simple", JaxrsTestApplication.class, initParams);
+ }
+
+ });
+
+ // Send GET request without token, it should fail
+ Response getResp = client.target(JAXRS_APP_URL).request().get();
+ Assert.assertEquals(getResp.getStatus(), 401);
+ getResp.close();
+
+ // Send POST request without token, it should fail
+ Response postResp = client.target(JAXRS_APP_URL).request().post(Entity.form(new Form()));
+ Assert.assertEquals(postResp.getStatus(), 401);
+ postResp.close();
+
+ // Retrieve token
+ OAuthClient.AccessTokenResponse accessTokenResp = retrieveAccessToken();
+ String authHeader = "Bearer " + accessTokenResp.getAccessToken();
+
+ // Send GET request with token and assert it's passing
+ JaxrsTestResource.SimpleRepresentation getRep = client.target(JAXRS_APP_URL).request()
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .get(JaxrsTestResource.SimpleRepresentation.class);
+ Assert.assertEquals("get", getRep.getMethod());
+ Assert.assertTrue(getRep.getHasUserRole());
+ Assert.assertFalse(getRep.getHasAdminRole());
+ Assert.assertFalse(getRep.getHasJaxrsAppRole());
+ // Assert that principal is ID of user (should be in UUID format)
+ UUID.fromString(getRep.getPrincipal());
+
+ // Send POST request with token and assert it's passing
+ JaxrsTestResource.SimpleRepresentation postRep = client.target(JAXRS_APP_URL).request()
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .post(Entity.form(new Form()), JaxrsTestResource.SimpleRepresentation.class);
+ Assert.assertEquals("post", postRep.getMethod());
+ Assert.assertEquals(getRep.getPrincipal(), postRep.getPrincipal());
+ }
+
+ @Test
+ public void testRelativeUriAndPublicKey() {
+ keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ Map<String,String> initParams = new TreeMap<String,String>();
+ initParams.put(CONFIG_FILE_INIT_PARAM, "classpath:jaxrs-test/jaxrs-keycloak-relative.json");
+ keycloakRule.deployJaxrsApplication("JaxrsSimpleApp", "/jaxrs-simple", JaxrsTestApplication.class, initParams);
+ }
+
+ });
+
+ // Send GET request without token, it should fail
+ Response getResp = client.target(JAXRS_APP_URL).request().get();
+ Assert.assertEquals(getResp.getStatus(), 401);
+ getResp.close();
+
+ // Retrieve token
+ OAuthClient.AccessTokenResponse accessTokenResp = retrieveAccessToken();
+ String authHeader = "Bearer " + accessTokenResp.getAccessToken();
+
+ // Send GET request with token and assert it's passing
+ JaxrsTestResource.SimpleRepresentation getRep = client.target(JAXRS_APP_URL).request()
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .get(JaxrsTestResource.SimpleRepresentation.class);
+ Assert.assertEquals("get", getRep.getMethod());
+ Assert.assertTrue(getRep.getHasUserRole());
+ Assert.assertFalse(getRep.getHasAdminRole());
+ Assert.assertFalse(getRep.getHasJaxrsAppRole());
+ // Assert that principal is ID of user (should be in UUID format)
+ UUID.fromString(getRep.getPrincipal());
+ }
+
+ @Test
+ public void testSslRequired() {
+ keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ Map<String, String> initParams = new TreeMap<String, String>();
+ initParams.put(CONFIG_FILE_INIT_PARAM, "classpath:jaxrs-test/jaxrs-keycloak-ssl.json");
+ keycloakRule.deployJaxrsApplication("JaxrsSimpleApp", "/jaxrs-simple", JaxrsTestApplication.class, initParams);
+ }
+
+ });
+
+ // Retrieve token
+ OAuthClient.AccessTokenResponse accessTokenResp = retrieveAccessToken();
+ String authHeader = "Bearer " + accessTokenResp.getAccessToken();
+
+ // Fail due to non-https
+ Response getResp = client.target(JAXRS_APP_URL).request()
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .get();
+ Assert.assertEquals(getResp.getStatus(), 403);
+ getResp.close();
+ }
+
+ @Test
+ public void testResourceRoleMappings() {
+ keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ Map<String, String> initParams = new TreeMap<String, String>();
+ initParams.put(CONFIG_FILE_INIT_PARAM, "classpath:jaxrs-test/jaxrs-keycloak-resource-mappings.json");
+ keycloakRule.deployJaxrsApplication("JaxrsSimpleApp", "/jaxrs-simple", JaxrsTestApplication.class, initParams);
+ }
+
+ });
+
+ // Retrieve token
+ OAuthClient.AccessTokenResponse accessTokenResp = retrieveAccessToken();
+ String authHeader = "Bearer " + accessTokenResp.getAccessToken();
+
+ // Send GET request with token and assert it's passing
+ JaxrsTestResource.SimpleRepresentation getRep = client.target(JAXRS_APP_URL).request()
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .get(JaxrsTestResource.SimpleRepresentation.class);
+ Assert.assertEquals("get", getRep.getMethod());
+
+ // principal is username
+ Assert.assertEquals("test-user@localhost", getRep.getPrincipal());
+
+ // User is in jaxrs-app-user role thanks to use-resource-role-mappings
+ Assert.assertFalse(getRep.getHasUserRole());
+ Assert.assertFalse(getRep.getHasAdminRole());
+ Assert.assertTrue(getRep.getHasJaxrsAppRole());
+ }
+
+ @Test
+ public void testCors() {
+ keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ Map<String,String> initParams = new TreeMap<String,String>();
+ initParams.put(CONFIG_FILE_INIT_PARAM, "classpath:jaxrs-test/jaxrs-keycloak.json");
+ keycloakRule.deployJaxrsApplication("JaxrsSimpleApp", "/jaxrs-simple", JaxrsTestApplication.class, initParams);
+ }
+
+ });
+
+ // Send OPTIONS request
+ Response optionsResp = client.target(JAXRS_APP_URL).request()
+ .header(CorsHeaders.ORIGIN, "http://localhost:8081")
+ .options();
+ Assert.assertEquals("true", optionsResp.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS));
+ Assert.assertEquals("http://localhost:8081", optionsResp.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN));
+ optionsResp.close();
+
+ // Retrieve token
+ OAuthClient.AccessTokenResponse accessTokenResp = retrieveAccessToken();
+ String authHeader = "Bearer " + accessTokenResp.getAccessToken();
+
+ // Send GET request with token but bad origin
+ Response badOriginResp = client.target(JAXRS_APP_URL).request()
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .header(CorsHeaders.ORIGIN, "http://evil.org")
+ .get();
+ Assert.assertEquals(403, badOriginResp.getStatus());
+ badOriginResp.close();
+
+ // Send GET request with token and good origin
+ Response goodResp = client.target(JAXRS_APP_URL).request()
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .header(CorsHeaders.ORIGIN, "http://localhost:8081")
+ .get();
+ Assert.assertEquals(200, goodResp.getStatus());
+ Assert.assertEquals("true", optionsResp.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS));
+ Assert.assertEquals("http://localhost:8081", optionsResp.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN));
+ JaxrsTestResource.SimpleRepresentation getRep = goodResp.readEntity(JaxrsTestResource.SimpleRepresentation.class);
+ Assert.assertEquals("get", getRep.getMethod());
+ goodResp.close();
+ }
+
+ @Test
+ public void testPushNotBefore() {
+ keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ Map<String,String> initParams = new TreeMap<String,String>();
+ initParams.put(CONFIG_FILE_INIT_PARAM, "classpath:jaxrs-test/jaxrs-keycloak.json");
+ keycloakRule.deployJaxrsApplication("JaxrsSimpleApp", "/jaxrs-simple", JaxrsTestApplication.class, initParams);
+ }
+
+ });
+
+ // Retrieve token
+ OAuthClient.AccessTokenResponse accessTokenResp = retrieveAccessToken();
+ String authHeader = "Bearer " + accessTokenResp.getAccessToken();
+
+ // Send GET request with token and assert it's passing
+ JaxrsTestResource.SimpleRepresentation getRep = client.target(JAXRS_APP_URL).request()
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .get(JaxrsTestResource.SimpleRepresentation.class);
+ Assert.assertEquals("get", getRep.getMethod());
+ Assert.assertTrue(getRep.getHasUserRole());
+
+ // Push new notBefore now TODO: should use admin console (admin client) instead..
+ int currentTime = Time.currentTime();
+ PushNotBeforeAction action = new PushNotBeforeAction(TokenIdGenerator.generateId(), currentTime + 30, "jaxrs-app", currentTime + 1);
+ String token = new TokenManager().encodeToken(appRealm, action);
+ Response response = client.target(JAXRS_APP_PUSN_NOT_BEFORE_URL).request().post(Entity.text(token));
+ Assert.assertEquals(204, response.getStatus());
+ response.close();
+
+ // Assert that previous token shouldn't pass anymore
+ response = client.target(JAXRS_APP_URL).request()
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .get();
+ Assert.assertEquals(401, response.getStatus());
+ response.close();
+ }
+
+ // @Test
+ public void testCxfExample() {
+ String uri = "http://localhost:9000/customerservice/customers/123";
+ Response resp = client.target(uri).request()
+ .get();
+ Assert.assertEquals(resp.getStatus(), 401);
+ resp.close();
+
+ // Retrieve token
+ OAuthClient.AccessTokenResponse accessTokenResp = retrieveAccessToken();
+ String authHeader = "Bearer " + accessTokenResp.getAccessToken();
+
+ String resp2 = client.target(uri).request()
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .get(String.class);
+ System.out.println(resp2);
+ }
+
+
+ private OAuthClient.AccessTokenResponse retrieveAccessToken() {
+ OAuthClient oauth = new OAuthClient(driver);
+ oauth.doLogin("test-user@localhost", "password");
+ String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+ OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
+ Assert.assertEquals(200, response.getStatusCode());
+ return response;
+ }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsTestApplication.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsTestApplication.java
new file mode 100644
index 0000000..787b9fd
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsTestApplication.java
@@ -0,0 +1,38 @@
+package org.keycloak.testsuite.jaxrs;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Context;
+
+import org.keycloak.jaxrs.JaxrsBearerTokenFilterImpl;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class JaxrsTestApplication extends Application {
+
+ protected Set<Class<?>> classes = new HashSet<Class<?>>();
+ protected Set<Object> singletons = new HashSet<Object>();
+
+ public JaxrsTestApplication(@Context ServletContext context) throws Exception {
+ singletons.add(new JaxrsTestResource());
+
+ String configFile = context.getInitParameter(JaxrsFilterTest.CONFIG_FILE_INIT_PARAM);
+ JaxrsBearerTokenFilterImpl filter = new JaxrsBearerTokenFilterImpl();
+ filter.setKeycloakConfigFile(configFile);
+ singletons.add(filter);
+ }
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ return classes;
+ }
+
+ @Override
+ public Set<Object> getSingletons() {
+ return singletons;
+ }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsTestResource.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsTestResource.java
new file mode 100644
index 0000000..6938d05
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsTestResource.java
@@ -0,0 +1,93 @@
+package org.keycloak.testsuite.jaxrs;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.SecurityContext;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@Path("res")
+public class JaxrsTestResource {
+
+ @Context
+ protected SecurityContext securityContext;
+
+ @GET
+ @Produces("application/json")
+ public SimpleRepresentation get() {
+ return new SimpleRepresentation("get", securityContext.getUserPrincipal().getName(), securityContext.isUserInRole("user"),
+ securityContext.isUserInRole("admin"), securityContext.isUserInRole("jaxrs-app-user"));
+ }
+
+ @POST
+ @Produces("application/json")
+ public SimpleRepresentation post() {
+ return new SimpleRepresentation("post", securityContext.getUserPrincipal().getName(), securityContext.isUserInRole("user"),
+ securityContext.isUserInRole("admin"), securityContext.isUserInRole("jaxrs-app-user"));
+ }
+
+ public static class SimpleRepresentation {
+ private String method;
+ private String principal;
+ private Boolean hasUserRole;
+ private Boolean hasAdminRole;
+ private Boolean hasJaxrsAppRole;
+
+ public SimpleRepresentation() {
+ }
+
+ public SimpleRepresentation(String method, String principal, boolean hasUserRole, boolean hasAdminRole,
+ boolean hasJaxrsAppRole) {
+ this.method = method;
+ this.principal = principal;
+ this.hasUserRole = hasUserRole;
+ this.hasAdminRole = hasAdminRole;
+ this.hasJaxrsAppRole = hasJaxrsAppRole;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public String getPrincipal() {
+ return principal;
+ }
+
+ public void setPrincipal(String principal) {
+ this.principal = principal;
+ }
+
+ public Boolean getHasUserRole() {
+ return hasUserRole;
+ }
+
+ public void setHasUserRole(Boolean hasUserRole) {
+ this.hasUserRole = hasUserRole;
+ }
+
+ public Boolean getHasAdminRole() {
+ return hasAdminRole;
+ }
+
+ public void setHasAdminRole(Boolean hasAdminRole) {
+ this.hasAdminRole = hasAdminRole;
+ }
+
+ public Boolean getHasJaxrsAppRole() {
+ return hasJaxrsAppRole;
+ }
+
+ public void setHasJaxrsAppRole(Boolean hasJaxrsAppRole) {
+ this.hasJaxrsAppRole = hasJaxrsAppRole;
+ }
+ }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
index 0808dcb..b89f2c3 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
@@ -1,10 +1,14 @@
package org.keycloak.testsuite.rule;
+import io.undertow.servlet.Servlets;
import io.undertow.servlet.api.DeploymentInfo;
+import io.undertow.servlet.api.FilterInfo;
import io.undertow.servlet.api.LoginConfig;
import io.undertow.servlet.api.SecurityConstraint;
import io.undertow.servlet.api.ServletInfo;
import io.undertow.servlet.api.WebResourceCollection;
+import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
+import org.jboss.resteasy.spi.ResteasyDeployment;
import org.junit.rules.ExternalResource;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
@@ -14,16 +18,23 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.services.filters.ClientConnectionFilter;
+import org.keycloak.services.filters.KeycloakSessionServletFilter;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.Retry;
import org.keycloak.testutils.KeycloakServer;
import org.keycloak.util.JsonSerialization;
+import javax.servlet.DispatcherType;
import javax.servlet.Servlet;
+import javax.ws.rs.core.Application;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
+import java.util.Map;
+
import org.keycloak.adapters.KeycloakConfigResolver;
/**
@@ -158,6 +169,22 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
server.getServer().deploy(di);
}
+ public void deployJaxrsApplication(String name, String contextPath, Class<? extends Application> applicationClass, Map<String,String> initParams) {
+ ResteasyDeployment deployment = new ResteasyDeployment();
+ deployment.setApplicationClass(applicationClass.getName());
+
+ DeploymentInfo di = server.getServer().undertowDeployment(deployment, "");
+ di.setClassLoader(getClass().getClassLoader());
+ di.setContextPath(contextPath);
+ di.setDeploymentName(name);
+
+ for (Map.Entry<String,String> param : initParams.entrySet()) {
+ di.addInitParameter(param.getKey(), param.getValue());
+ }
+
+ server.getServer().deploy(di);
+ }
+
@Override
protected void after() {
removeTestRealms();
diff --git a/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak.json b/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak.json
new file mode 100644
index 0000000..5a83668
--- /dev/null
+++ b/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak.json
@@ -0,0 +1,9 @@
+{
+ "realm": "test",
+ "resource": "jaxrs-app",
+ "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "http://localhost:8081/auth",
+ "ssl-required" : "external",
+ "bearer-only": true,
+ "enable-cors": true
+}
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak-relative.json b/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak-relative.json
new file mode 100644
index 0000000..a17933e
--- /dev/null
+++ b/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak-relative.json
@@ -0,0 +1,7 @@
+{
+ "realm": "test",
+ "resource": "jaxrs-app",
+ "auth-server-url": "/auth",
+ "ssl-required" : "external",
+ "bearer-only": true
+}
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak-resource-mappings.json b/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak-resource-mappings.json
new file mode 100644
index 0000000..924e4ad
--- /dev/null
+++ b/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak-resource-mappings.json
@@ -0,0 +1,10 @@
+{
+ "realm": "test",
+ "resource": "jaxrs-app",
+ "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "http://localhost:8081/auth",
+ "ssl-required" : "external",
+ "bearer-only": true,
+ "principal-attribute": "preferred_username",
+ "use-resource-role-mappings": true
+}
diff --git a/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak-ssl.json b/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak-ssl.json
new file mode 100644
index 0000000..666ddb9
--- /dev/null
+++ b/testsuite/integration/src/test/resources/jaxrs-test/jaxrs-keycloak-ssl.json
@@ -0,0 +1,8 @@
+{
+ "realm": "test",
+ "resource": "jaxrs-app",
+ "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "http://localhost:8081/auth",
+ "ssl-required" : "all",
+ "bearer-only": true
+}
\ No newline at end of file
diff --git a/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/PerfAppServlet.java b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/PerfAppServlet.java
index 5fd6c01..cfbe9e1 100755
--- a/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/PerfAppServlet.java
+++ b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/PerfAppServlet.java
@@ -4,7 +4,7 @@ import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
-import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.constants.AdapterConstants;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.RefreshToken;
import org.keycloak.util.Time;
diff --git a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
index 791e0d3..18b1de7 100755
--- a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
+++ b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
@@ -36,7 +36,6 @@ import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.OpenIDConnectService;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.services.resources.admin.AdminRoot;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.rule.WebResource;
@@ -48,18 +47,12 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriBuilder;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.security.Principal;
-import java.util.Map;
import java.util.regex.Matcher;
/**