keycloak-aplcache

Merge pull request #2534 from stianst/admin-client-prs-1.9 Add

4/7/2016 4:06:59 AM

Details

diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
index 92655e0..52c5561 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
@@ -46,7 +46,7 @@ public class Keycloak {
 
     Keycloak(String serverUrl, String realm, String username, String password, String clientId, String clientSecret, ResteasyClient resteasyClient){
         config = new Config(serverUrl, realm, username, password, clientId, clientSecret);
-        client = resteasyClient != null ? resteasyClient : new ResteasyClientBuilder().build();
+        client = resteasyClient != null ? resteasyClient : new ResteasyClientBuilder().connectionPoolSize(10).build();
 
         tokenManager = new TokenManager(config, client);
 
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/BearerAuthFilter.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/BearerAuthFilter.java
index ff5315b..514aeea 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/BearerAuthFilter.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/BearerAuthFilter.java
@@ -21,14 +21,18 @@ import org.keycloak.admin.client.token.TokenManager;
 
 import javax.ws.rs.client.ClientRequestContext;
 import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.ClientResponseContext;
+import javax.ws.rs.client.ClientResponseFilter;
 import javax.ws.rs.core.HttpHeaders;
 import java.io.IOException;
+import java.util.List;
 
 /**
  * @author rodrigo.sasaki@icarros.com.br
  */
-public class BearerAuthFilter implements ClientRequestFilter {
+public class BearerAuthFilter implements ClientRequestFilter, ClientResponseFilter {
 
+    public static final String AUTH_HEADER_PREFIX = "Bearer ";
     private final String tokenString;
     private final TokenManager tokenManager;
 
@@ -45,9 +49,27 @@ public class BearerAuthFilter implements ClientRequestFilter {
 
     @Override
     public void filter(ClientRequestContext requestContext) throws IOException {
-        String authHeader = "Bearer " + (tokenManager != null ? tokenManager.getAccessTokenString() : tokenString);
+        String authHeader = AUTH_HEADER_PREFIX + (tokenManager != null ? tokenManager.getAccessTokenString() : tokenString);
 
         requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
     }
 
+    @Override
+    public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
+        if (responseContext.getStatus() == 401 && tokenManager != null) {
+            List<Object> authHeaders = requestContext.getHeaders().get(HttpHeaders.AUTHORIZATION);
+            if (authHeaders == null) {
+                return;
+            }
+            for (Object authHeader : authHeaders) {
+                if (authHeader instanceof String) {
+                    String headerValue = (String) authHeader;
+                    if (headerValue.startsWith(AUTH_HEADER_PREFIX)) {
+                        String token = headerValue.substring( AUTH_HEADER_PREFIX.length() );
+                        tokenManager.invalidate( token );
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
index 02056a7..e325681 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
@@ -18,7 +18,6 @@
 package org.keycloak.admin.client.token;
 
 import org.jboss.resteasy.client.jaxrs.ResteasyClient;
-import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
 import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
 import org.keycloak.admin.client.Config;
 import org.keycloak.admin.client.resource.BasicAuthFilter;
@@ -27,8 +26,6 @@ import org.keycloak.representations.AccessTokenResponse;
 
 import javax.ws.rs.BadRequestException;
 import javax.ws.rs.core.Form;
-import java.util.Calendar;
-import java.util.Date;
 
 /**
  * @author rodrigo.sasaki@icarros.com.br
@@ -41,18 +38,22 @@ public class TokenManager {
     private long expirationTime;
     private long minTokenValidity = DEFAULT_MIN_VALIDITY;
     private final Config config;
-    private final ResteasyClient client;
+    private final TokenService tokenService;
 
     public TokenManager(Config config, ResteasyClient client){
         this.config = config;
-        this.client = client;
+        ResteasyWebTarget target = client.target(config.getServerUrl());
+        if(!config.isPublicClient()){
+            target.register(new BasicAuthFilter(config.getClientId(), config.getClientSecret()));
+        }
+        tokenService = target.proxy(TokenService.class);
     }
 
     public String getAccessTokenString(){
         return getAccessToken().getToken();
     }
 
-    public AccessTokenResponse getAccessToken(){
+    public synchronized AccessTokenResponse getAccessToken(){
         if(currentToken == null){
             grantToken();
         }else if(tokenExpired()){
@@ -62,8 +63,6 @@ public class TokenManager {
     }
 
     public AccessTokenResponse grantToken(){
-        ResteasyWebTarget target = client.target(config.getServerUrl());
-
         Form form = new Form()
                 .param("grant_type", "password")
                 .param("username", config.getUsername())
@@ -71,51 +70,58 @@ public class TokenManager {
 
         if(config.isPublicClient()){
             form.param("client_id", config.getClientId());
-        } else {
-            target.register(new BasicAuthFilter(config.getClientId(), config.getClientSecret()));
         }
 
-        TokenService tokenService = target.proxy(TokenService.class);
-
         int requestTime = Time.currentTime();
-        currentToken = tokenService.grantToken(config.getRealm(), form.asMap());
-        expirationTime = requestTime + currentToken.getExpiresIn();
-
+        synchronized (this) {
+            currentToken = tokenService.grantToken( config.getRealm(), form.asMap() );
+            expirationTime = requestTime + currentToken.getExpiresIn();
+        }
         return currentToken;
     }
 
     public AccessTokenResponse refreshToken(){
-        ResteasyWebTarget target = client.target(config.getServerUrl());
-
         Form form = new Form()
                 .param("grant_type", "refresh_token")
                 .param("refresh_token", currentToken.getRefreshToken());
 
         if(config.isPublicClient()){
             form.param("client_id", config.getClientId());
-        } else {
-            target.register(new BasicAuthFilter(config.getClientId(), config.getClientSecret()));
         }
 
-        TokenService tokenService = target.proxy(TokenService.class);
-
         try {
             int requestTime = Time.currentTime();
-            currentToken = tokenService.refreshToken(config.getRealm(), form.asMap());
-            expirationTime = requestTime + currentToken.getExpiresIn();
 
+            synchronized (this) {
+                currentToken = tokenService.refreshToken( config.getRealm(), form.asMap() );
+                expirationTime = requestTime + currentToken.getExpiresIn();
+            }
             return currentToken;
         } catch (BadRequestException e) {
             return grantToken();
         }
     }
 
-    public void setMinTokenValidity(long minTokenValidity) {
+    public synchronized void setMinTokenValidity(long minTokenValidity) {
         this.minTokenValidity = minTokenValidity;
     }
 
-    private boolean tokenExpired() {
+    private synchronized boolean tokenExpired() {
         return (Time.currentTime() + minTokenValidity) >= expirationTime;
     }
 
+    /**
+     * Invalidates the current token, but only when it is equal to the token passed as an argument.
+     *
+     * @param token the token to invalidate (cannot be null).
+     */
+    public void invalidate(String token) {
+        if (currentToken == null) {
+            return; // There's nothing to invalidate.
+        }
+        if (token.equals(currentToken.getToken())) {
+            // When used next, this cause a refresh attempt, that in turn will cause a grant attempt if refreshing fails.
+            expirationTime = -1;
+        }
+    }
 }