keycloak-aplcache

Details

diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
index fd54ce2..7f62fd1 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
@@ -17,7 +17,7 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
         "connection-pool-size",
         "allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password",
         "client-keystore", "client-keystore-password", "client-key-password",
-        "auth-server-url-for-backend-requests"
+        "auth-server-url-for-backend-requests", "always-refresh-token"
 })
 public class AdapterConfig extends BaseAdapterConfig {
 
@@ -39,6 +39,8 @@ public class AdapterConfig extends BaseAdapterConfig {
     protected int connectionPoolSize = 20;
     @JsonProperty("auth-server-url-for-backend-requests")
     protected String authServerUrlForBackendRequests;
+    @JsonProperty("always-refresh-token")
+    protected boolean alwaysRefreshToken = false;
 
     public boolean isAllowAnyHostname() {
         return allowAnyHostname;
@@ -111,4 +113,12 @@ public class AdapterConfig extends BaseAdapterConfig {
     public void setAuthServerUrlForBackendRequests(String authServerUrlForBackendRequests) {
         this.authServerUrlForBackendRequests = authServerUrlForBackendRequests;
     }
+
+    public boolean isAlwaysRefreshToken() {
+        return alwaysRefreshToken;
+    }
+
+    public void setAlwaysRefreshToken(boolean alwaysRefreshToken) {
+        this.alwaysRefreshToken = alwaysRefreshToken;
+    }
 }
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
index f1e5292..69e61aa 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
@@ -326,6 +326,16 @@ public class AdapterDeploymentContext {
         public void setCorsAllowedHeaders(String corsAllowedHeaders) {
             delegate.setCorsAllowedHeaders(corsAllowedHeaders);
         }
+
+        @Override
+        public boolean isAlwaysRefreshToken() {
+            return delegate.isAlwaysRefreshToken();
+        }
+
+        @Override
+        public void setAlwaysRefreshToken(boolean alwaysRefreshToken) {
+            delegate.setAlwaysRefreshToken(alwaysRefreshToken);
+        }
     }
 
     protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) {
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 db284b1..c376112 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
@@ -47,6 +47,7 @@ public class KeycloakDeployment {
     protected String corsAllowedHeaders;
     protected String corsAllowedMethods;
     protected boolean exposeToken;
+    protected boolean alwaysRefreshToken;
     protected volatile int notBefore;
 
     public KeycloakDeployment() {
@@ -281,4 +282,11 @@ public class KeycloakDeployment {
         this.notBefore = notBefore;
     }
 
+    public boolean isAlwaysRefreshToken() {
+        return alwaysRefreshToken;
+    }
+
+    public void setAlwaysRefreshToken(boolean alwaysRefreshToken) {
+        this.alwaysRefreshToken = alwaysRefreshToken;
+    }
 }
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index 5aa996b..6e5c29f 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -35,7 +35,7 @@ public class KeycloakDeploymentBuilder {
 
         String realmKeyPem = adapterConfig.getRealmKey();
         if (realmKeyPem != null) {
-            PublicKey realmKey = null;
+            PublicKey realmKey;
             try {
                 realmKey = PemUtils.decodePublicKey(realmKeyPem);
             } catch (Exception e) {
@@ -60,9 +60,7 @@ public class KeycloakDeploymentBuilder {
         }
 
         deployment.setBearerOnly(adapterConfig.isBearerOnly());
-
-        if (adapterConfig.isBearerOnly()) {
-        }
+        deployment.setAlwaysRefreshToken(adapterConfig.isAlwaysRefreshToken());
 
         if (realmKeyPem == null && adapterConfig.isBearerOnly() && adapterConfig.getAuthServerUrl() == null) {
             throw new IllegalArgumentException("For bearer auth, you must set the realm-public-key or auth-server-url");
@@ -82,7 +80,7 @@ public class KeycloakDeploymentBuilder {
     public static KeycloakDeployment build(InputStream is) {
         ObjectMapper mapper = new ObjectMapper(new SystemPropertiesJsonParserFactory());
         mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
-        AdapterConfig adapterConfig = null;
+        AdapterConfig adapterConfig;
         try {
             adapterConfig = mapper.readValue(is, AdapterConfig.class);
         } catch (IOException e) {
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
index 7dfe62c..3fc5b3d 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
@@ -32,13 +32,13 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
 
     @Override
     public AccessToken getToken() {
-        refreshExpiredToken();
+        refreshExpiredToken(true);
         return super.getToken();
     }
 
     @Override
     public String getTokenString() {
-        refreshExpiredToken();
+        refreshExpiredToken(true);
         return super.getTokenString();
     }
 
@@ -62,12 +62,19 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
         this.deployment = deployment;
     }
 
-    public void refreshExpiredToken() {
-        if (log.isTraceEnabled()) {
-            log.trace("checking whether to refresh.");
+    /**
+     * @param checkActive if true, then we won't send refresh request if current accessToken is still active.
+     * @return true if accessToken is active or was successfully refreshed
+     */
+    public boolean refreshExpiredToken(boolean checkActive) {
+        if (checkActive) {
+            if (log.isTraceEnabled()) {
+                log.trace("checking whether to refresh.");
+            }
+            if (isActive()) return true;
         }
-        if (isActive()) return;
-        if (this.deployment == null || refreshToken == null) return; // Might be serialized in HttpSession?
+
+        if (this.deployment == null || refreshToken == null) return false; // Might be serialized in HttpSession?
 
         if (log.isTraceEnabled()) {
             log.trace("Doing refresh");
@@ -77,10 +84,10 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
             response = ServerRequest.invokeRefresh(deployment, refreshToken);
         } catch (IOException e) {
             log.error("Refresh token failure", e);
-            return;
+            return false;
         } catch (ServerRequest.HttpFailure httpFailure) {
             log.error("Refresh token failure status: " + httpFailure.getStatus() + " " + httpFailure.getError());
-            return;
+            return false;
         }
         if (log.isTraceEnabled()) {
             log.trace("received refresh response");
@@ -100,7 +107,7 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
         this.token = token;
         this.refreshToken = response.getRefreshToken();
         this.tokenString = tokenString;
-
+        return true;
     }
 
 
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 eb39756..7392270 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
@@ -175,12 +175,12 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
         if (session == null) return;
         // just in case session got serialized
         if (session.getDeployment() == null) session.setDeployment(deploymentContext.resolveDeployment(facade));
-        if (session.isActive()) return;
+        if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) return;
 
         // FYI: A refresh requires same scope, so same roles will be set.  Otherwise, refresh will fail and token will
         // not be updated
-        session.refreshExpiredToken();
-        if (session.isActive()) return;
+        boolean success = session.refreshExpiredToken(false);
+        if (success && session.isActive()) return;
 
         request.getSessionInternal().removeNote(KeycloakSecurityContext.class.getName());
         request.setUserPrincipal(null);
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 2fd8be4..2905c8f 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
@@ -177,12 +177,12 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
         if (session == null) return;
         // just in case session got serialized
         if (session.getDeployment() == null) session.setDeployment(deploymentContext.resolveDeployment(facade));
-        if (session.isActive()) return;
+        if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) return;
 
         // FYI: A refresh requires same scope, so same roles will be set.  Otherwise, refresh will fail and token will
         // not be updated
-        session.refreshExpiredToken();
-        if (session.isActive()) return;
+        boolean success = session.refreshExpiredToken(false);
+        if (success && session.isActive()) return;
 
         request.getSessionInternal().removeNote(KeycloakSecurityContext.class.getName());
         request.setUserPrincipal(null);
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java
index 58cbb02..472bc90 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java
@@ -92,14 +92,14 @@ public class KeycloakUndertowAccount implements Account, Serializable, KeycloakA
     public boolean isActive() {
         // this object may have been serialized, so we need to reset realm config/metadata
         RefreshableKeycloakSecurityContext session = getKeycloakSecurityContext();
-        if (session.isActive()) {
+        if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) {
             log.debug("session is active");
             return true;
         }
 
-        log.debug("session is not active try refresh");
-        session.refreshExpiredToken();
-        if (!session.isActive()) {
+        log.debug("session is not active or refresh is enforced. Try refresh");
+        boolean success = session.refreshExpiredToken(false);
+        if (!success || !session.isActive()) {
             log.debug("session is not active return with failure");
 
             return false;
diff --git a/testsuite/docker-cluster/shared-files/deploy-examples.sh b/testsuite/docker-cluster/shared-files/deploy-examples.sh
index 10f9643..efc54ca 100644
--- a/testsuite/docker-cluster/shared-files/deploy-examples.sh
+++ b/testsuite/docker-cluster/shared-files/deploy-examples.sh
@@ -23,6 +23,10 @@ done;
 # Configure admin-access.war
 sed -i -e 's/false/true/' admin-access.war/WEB-INF/web.xml
 
+# Enforce refreshing token for product-portal and customer-portal war
+sed -i -e 's/\"\/auth\",/&\n    \"always-refresh-token\": true,/' customer-portal.war/WEB-INF/keycloak.json;
+sed -i -e 's/\"\/auth\",/&\n    \"always-refresh-token\": true,/' product-portal.war/WEB-INF/keycloak.json;
+
 # Configure other examples
 for I in *.war/WEB-INF/keycloak.json; do
   sed -i -e 's/\"\/auth\",/&\n    \"auth-server-url-for-backend-requests\": \"http:\/\/\$\{jboss.host.name\}:8080\/auth\",/' $I;