keycloak-aplcache

Changes

Details

diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java
index eebf18d..3cf3242 100755
--- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java
@@ -5,6 +5,7 @@ import org.keycloak.broker.provider.BrokeredIdentityContext;
 import org.keycloak.constants.AdapterConstants;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.representations.AccessTokenResponse;
@@ -51,7 +52,13 @@ public class KeycloakOIDCIdentityProvider extends OIDCIdentityProvider {
         @POST
         @Path(AdapterConstants.K_LOGOUT)
         public Response backchannelLogout(String input) {
-            JWSInput token = new JWSInput(input);
+            JWSInput token = null;
+            try {
+                token = new JWSInput(input);
+            } catch (JWSInputException e) {
+                logger.warn("Failed to verify logout request");
+                return Response.status(400).build();
+            }
             PublicKey key = getExternalIdpKey();
             if (key != null) {
                 if (!verify(token, key)) {
diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
index 4d5b45e..6938c11 100755
--- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
@@ -29,6 +29,7 @@ import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.RealmModel;
@@ -282,40 +283,41 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
             throw new IdentityBrokerException("No token from server.");
         }
 
+        JsonWebToken token;
         try {
             JWSInput jws = new JWSInput(encodedToken);
             if (!verify(jws, key)) {
                 throw new IdentityBrokerException("token signature validation failed");
             }
-            JsonWebToken token = jws.readJsonContent(JsonWebToken.class);
+            token = jws.readJsonContent(JsonWebToken.class);
+        } catch (JWSInputException e) {
+            throw new IdentityBrokerException("Invalid token", e);
+        }
 
-            String iss = token.getIssuer();
+        String iss = token.getIssuer();
 
-            if (!token.hasAudience(getConfig().getClientId())) {
-                throw new IdentityBrokerException("Wrong audience from token.");
-            }
+        if (!token.hasAudience(getConfig().getClientId())) {
+            throw new IdentityBrokerException("Wrong audience from token.");
+        }
 
-            if (!token.isActive()) {
-                throw new IdentityBrokerException("Token is no longer valid");
-            }
+        if (!token.isActive()) {
+            throw new IdentityBrokerException("Token is no longer valid");
+        }
 
-            String trustedIssuers = getConfig().getIssuer();
+        String trustedIssuers = getConfig().getIssuer();
 
-            if (trustedIssuers != null) {
-                String[] issuers = trustedIssuers.split(",");
+        if (trustedIssuers != null) {
+            String[] issuers = trustedIssuers.split(",");
 
-                for (String trustedIssuer : issuers) {
-                    if (iss != null && iss.equals(trustedIssuer.trim())) {
-                        return token;
-                    }
+            for (String trustedIssuer : issuers) {
+                if (iss != null && iss.equals(trustedIssuer.trim())) {
+                    return token;
                 }
-
-                throw new IdentityBrokerException("Wrong issuer from token. Got: " + iss + " expected: " + getConfig().getIssuer());
             }
-            return token;
-        } catch (IOException e) {
-            throw new IdentityBrokerException("Could not decode token.", e);
+
+            throw new IdentityBrokerException("Wrong issuer from token. Got: " + iss + " expected: " + getConfig().getIssuer());
         }
+        return token;
     }
 
     @Override
diff --git a/core/src/main/java/org/keycloak/jose/jws/crypto/RSAProvider.java b/core/src/main/java/org/keycloak/jose/jws/crypto/RSAProvider.java
index 59e25ee..dc0e4e3 100755
--- a/core/src/main/java/org/keycloak/jose/jws/crypto/RSAProvider.java
+++ b/core/src/main/java/org/keycloak/jose/jws/crypto/RSAProvider.java
@@ -64,7 +64,7 @@ public class RSAProvider implements SignatureProvider {
             verifier.update(input.getEncodedSignatureInput().getBytes("UTF-8"));
             return verifier.verify(input.getSignature());
         } catch (Exception e) {
-            throw new RuntimeException(e);
+            return false;
         }
 
     }
diff --git a/core/src/main/java/org/keycloak/jose/jws/JWSInput.java b/core/src/main/java/org/keycloak/jose/jws/JWSInput.java
index b01355f..84f303d 100755
--- a/core/src/main/java/org/keycloak/jose/jws/JWSInput.java
+++ b/core/src/main/java/org/keycloak/jose/jws/JWSInput.java
@@ -21,14 +21,14 @@ public class JWSInput {
     byte[] signature;
 
 
-    public JWSInput(String wire) {
-        this.wireString = wire;
-        String[] parts = wire.split("\\.");
-        if (parts.length < 2 || parts.length > 3) throw new IllegalArgumentException("Parsing error");
-        encodedHeader = parts[0];
-        encodedContent = parts[1];
-        encodedSignatureInput = encodedHeader + '.' + encodedContent;
+    public JWSInput(String wire) throws JWSInputException {
         try {
+            this.wireString = wire;
+            String[] parts = wire.split("\\.");
+            if (parts.length < 2 || parts.length > 3) throw new IllegalArgumentException("Parsing error");
+            encodedHeader = parts[0];
+            encodedContent = parts[1];
+            encodedSignatureInput = encodedHeader + '.' + encodedContent;
             content = Base64Url.decode(encodedContent);
             if (parts.length > 2) {
                 encodedSignature = parts[2];
@@ -37,8 +37,8 @@ public class JWSInput {
             }
             byte[] headerBytes = Base64Url.decode(encodedHeader);
             header = JsonSerialization.readValue(headerBytes, JWSHeader.class);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
+        } catch (Throwable t) {
+            throw new JWSInputException(t);
         }
     }
 
@@ -80,8 +80,12 @@ public class JWSInput {
         return header.getAlgorithm().getProvider().verify(this, key);
     }
 
-    public <T> T readJsonContent(Class<T> type) throws IOException {
-        return JsonSerialization.readValue(content, type);
+    public <T> T readJsonContent(Class<T> type) throws JWSInputException {
+        try {
+            return JsonSerialization.readValue(content, type);
+        } catch (IOException e) {
+            throw new JWSInputException(e);
+        }
     }
 
     public String readContentAsString() {
diff --git a/core/src/main/java/org/keycloak/jose/jws/JWSInputException.java b/core/src/main/java/org/keycloak/jose/jws/JWSInputException.java
new file mode 100644
index 0000000..930a0b6
--- /dev/null
+++ b/core/src/main/java/org/keycloak/jose/jws/JWSInputException.java
@@ -0,0 +1,18 @@
+package org.keycloak.jose.jws;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class JWSInputException extends Exception {
+
+    public JWSInputException(String s) {
+        super(s);
+    }
+
+    public JWSInputException() {
+    }
+
+    public JWSInputException(Throwable throwable) {
+        super(throwable);
+    }
+}
diff --git a/core/src/main/java/org/keycloak/RSATokenVerifier.java b/core/src/main/java/org/keycloak/RSATokenVerifier.java
index f177166..19babef 100755
--- a/core/src/main/java/org/keycloak/RSATokenVerifier.java
+++ b/core/src/main/java/org/keycloak/RSATokenVerifier.java
@@ -2,6 +2,7 @@ package org.keycloak;
 
 import org.keycloak.common.VerificationException;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.util.TokenUtil;
@@ -22,7 +23,7 @@ public class RSATokenVerifier {
         JWSInput input = null;
         try {
             input = new JWSInput(tokenString);
-        } catch (Exception e) {
+        } catch (JWSInputException e) {
             throw new VerificationException("Couldn't parse token", e);
         }
         if (!isPublicKeyValid(input, realmKey)) throw new VerificationException("Invalid token signature.");
@@ -30,7 +31,7 @@ public class RSATokenVerifier {
         AccessToken token;
         try {
             token = input.readJsonContent(AccessToken.class);
-        } catch (IOException e) {
+        } catch (JWSInputException e) {
             throw new VerificationException("Couldn't parse token signature", e);
         }
         String user = token.getSubject();
diff --git a/core/src/main/java/org/keycloak/util/TokenUtil.java b/core/src/main/java/org/keycloak/util/TokenUtil.java
index 10b6c20..94f6a73 100644
--- a/core/src/main/java/org/keycloak/util/TokenUtil.java
+++ b/core/src/main/java/org/keycloak/util/TokenUtil.java
@@ -4,6 +4,7 @@ import java.io.IOException;
 
 import org.keycloak.OAuth2Constants;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.representations.RefreshToken;
 
 /**
@@ -41,11 +42,15 @@ public class TokenUtil {
      * @param decodedToken
      * @return
      */
-    public static RefreshToken getRefreshToken(byte[] decodedToken) throws IOException {
-        return JsonSerialization.readValue(decodedToken, RefreshToken.class);
+    public static RefreshToken getRefreshToken(byte[] decodedToken) throws JWSInputException {
+        try {
+            return JsonSerialization.readValue(decodedToken, RefreshToken.class);
+        } catch (IOException e) {
+            throw new JWSInputException(e);
+        }
     }
 
-    public static RefreshToken getRefreshToken(String refreshToken) throws IOException {
+    public static RefreshToken getRefreshToken(String refreshToken) throws JWSInputException {
         byte[] encodedContent = new JWSInput(refreshToken).getContent();
         return getRefreshToken(encodedContent);
     }
@@ -56,13 +61,9 @@ public class TokenUtil {
      * @param refreshToken
      * @return
      */
-    public static boolean isOfflineToken(String refreshToken) {
-        try {
-            RefreshToken token = getRefreshToken(refreshToken);
-            return token.getType().equals(TOKEN_TYPE_OFFLINE);
-        } catch (IOException ioe) {
-            throw new RuntimeException(ioe);
-        }
+    public static boolean isOfflineToken(String refreshToken) throws JWSInputException {
+        RefreshToken token = getRefreshToken(refreshToken);
+        return token.getType().equals(TOKEN_TYPE_OFFLINE);
     }
 
 }
diff --git a/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java b/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java
index 1143968..2583ec4 100755
--- a/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java
+++ b/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java
@@ -23,6 +23,7 @@ import org.keycloak.adapters.KeycloakDeployment;
 import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
 import org.keycloak.adapters.ServerRequest;
 import org.keycloak.adapters.spi.LogoutError;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.RefreshToken;
 import org.keycloak.util.JsonSerialization;
@@ -49,40 +50,44 @@ public class OfflineAccessPortalServlet extends HttpServlet {
 
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        try {
+            if (req.getRequestURI().endsWith("/login")) {
+                storeToken(req);
+                req.getRequestDispatcher("/WEB-INF/pages/loginCallback.jsp").forward(req, resp);
+                return;
+            }
 
-        if (req.getRequestURI().endsWith("/login")) {
-            storeToken(req);
-            req.getRequestDispatcher("/WEB-INF/pages/loginCallback.jsp").forward(req, resp);
-            return;
-        }
+            String refreshToken = RefreshTokenDAO.loadToken();
+            String refreshTokenInfo;
+            boolean savedTokenAvailable;
+            if (refreshToken == null) {
+                refreshTokenInfo = "No token saved in database. Please login first";
+                savedTokenAvailable = false;
+            } else {
+                RefreshToken refreshTokenDecoded = null;
+                    refreshTokenDecoded = TokenUtil.getRefreshToken(refreshToken);
+                String exp = (refreshTokenDecoded.getExpiration() == 0) ? "NEVER" : Time.toDate(refreshTokenDecoded.getExpiration()).toString();
+                refreshTokenInfo = String.format("<p>Type: %s</p><p>ID: %s</p><p>Expires: %s</p>", refreshTokenDecoded.getType(), refreshTokenDecoded.getId(), exp);
+                savedTokenAvailable = true;
+            }
+            req.setAttribute("tokenInfo", refreshTokenInfo);
+            req.setAttribute("savedTokenAvailable", savedTokenAvailable);
 
-        String refreshToken = RefreshTokenDAO.loadToken();
-        String refreshTokenInfo;
-        boolean savedTokenAvailable;
-        if (refreshToken == null) {
-            refreshTokenInfo = "No token saved in database. Please login first";
-            savedTokenAvailable = false;
-        } else {
-            RefreshToken refreshTokenDecoded = TokenUtil.getRefreshToken(refreshToken);
-            String exp = (refreshTokenDecoded.getExpiration() == 0) ? "NEVER" : Time.toDate(refreshTokenDecoded.getExpiration()).toString();
-            refreshTokenInfo = String.format("<p>Type: %s</p><p>ID: %s</p><p>Expires: %s</p>", refreshTokenDecoded.getType(), refreshTokenDecoded.getId(), exp);
-            savedTokenAvailable = true;
-        }
-        req.setAttribute("tokenInfo", refreshTokenInfo);
-        req.setAttribute("savedTokenAvailable", savedTokenAvailable);
-
-        String customers;
-        if (req.getRequestURI().endsWith("/loadCustomers")) {
-            customers = loadCustomers(req, refreshToken);
-        } else {
-            customers = "";
-        }
-        req.setAttribute("customers", customers);
+            String customers;
+            if (req.getRequestURI().endsWith("/loadCustomers")) {
+                customers = loadCustomers(req, refreshToken);
+            } else {
+                customers = "";
+            }
+            req.setAttribute("customers", customers);
 
-        req.getRequestDispatcher("/WEB-INF/pages/view.jsp").forward(req, resp);
+            req.getRequestDispatcher("/WEB-INF/pages/view.jsp").forward(req, resp);
+        } catch (JWSInputException e) {
+            throw new ServletException(e);
+        }
     }
 
-    private void storeToken(HttpServletRequest req) throws IOException {
+    private void storeToken(HttpServletRequest req) throws IOException, JWSInputException {
         RefreshableKeycloakSecurityContext ctx = (RefreshableKeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
         String refreshToken = ctx.getRefreshToken();
 
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 b1bd124..b385592 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
@@ -9,6 +9,7 @@ import org.keycloak.adapters.spi.HttpFacade;
 import org.keycloak.common.VerificationException;
 import org.keycloak.constants.AdapterConstants;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.IDToken;
 import org.keycloak.common.util.KeycloakUriBuilder;
@@ -58,10 +59,10 @@ public class CookieTokenStore {
             AccessToken accessToken = RSATokenVerifier.verifyToken(accessTokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl(), false, true);
             IDToken idToken;
             if (idTokenString != null && idTokenString.length() > 0) {
-                JWSInput input = new JWSInput(idTokenString);
                 try {
+                    JWSInput input = new JWSInput(idTokenString);
                     idToken = input.readJsonContent(IDToken.class);
-                } catch (IOException e) {
+                } catch (JWSInputException e) {
                     throw new VerificationException(e);
                 }
             } else {
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
index f41f80f..cc6b188 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
@@ -11,6 +11,7 @@ import org.keycloak.common.VerificationException;
 import org.keycloak.constants.AdapterConstants;
 import org.keycloak.enums.TokenStore;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.IDToken;
@@ -313,10 +314,10 @@ public class OAuthRequestAuthenticator {
         try {
             token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
             if (idTokenString != null) {
-                JWSInput input = new JWSInput(idTokenString);
                 try {
+                    JWSInput input = new JWSInput(idTokenString);
                     idToken = input.readJsonContent(IDToken.class);
-                } catch (IOException e) {
+                } catch (JWSInputException e) {
                     throw new VerificationException();
                 }
             }
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 2588c40..a332f83 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
@@ -3,6 +3,7 @@ package org.keycloak.adapters;
 import org.jboss.logging.Logger;
 import org.keycloak.adapters.spi.HttpFacade;
 import org.keycloak.adapters.spi.UserSessionManagement;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.representations.VersionRepresentation;
 import org.keycloak.constants.AdapterConstants;
 import org.keycloak.jose.jws.JWSInput;
@@ -178,18 +179,17 @@ public class PreAuthActionsHandler {
             return null;
         }
 
-        JWSInput input = new JWSInput(token);
-        boolean verified = false;
         try {
-            verified = RSAProvider.verify(input, deployment.getRealmKey());
-        } catch (Exception ignore) {
-        }
-        if (!verified) {
-            log.warn("admin request failed, unable to verify token");
-            facade.getResponse().sendError(403, "no token");
-            return null;
+            JWSInput input = new JWSInput(token);
+            if (RSAProvider.verify(input, deployment.getRealmKey())) {
+                return input;
+            }
+        } catch (JWSInputException ignore) {
         }
-        return input;
+
+        log.warn("admin request failed, unable to verify token");
+        facade.getResponse().sendError(403, "no token");
+        return null;
     }
 
 
diff --git a/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java b/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
index c468f8d..652860b 100644
--- a/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
+++ b/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
@@ -8,6 +8,7 @@ import org.keycloak.adapters.KeycloakDeployment;
 import org.keycloak.adapters.KeycloakDeploymentBuilder;
 import org.keycloak.adapters.ServerRequest;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.IDToken;
@@ -195,10 +196,10 @@ public class KeycloakInstalled {
 
         token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
         if (idTokenString != null) {
-            JWSInput input = new JWSInput(idTokenString);
             try {
+                JWSInput input = new JWSInput(idTokenString);
                 idToken = input.readJsonContent(IDToken.class);
-            } catch (IOException e) {
+            } catch (JWSInputException e) {
                 throw new VerificationException();
             }
         }
diff --git a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
index 9c54ab1..be92dea 100755
--- a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
+++ b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
@@ -9,6 +9,7 @@ import org.keycloak.adapters.ServerRequest;
 import org.keycloak.adapters.spi.AuthenticationError;
 import org.keycloak.adapters.spi.LogoutError;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.IDToken;
 import org.keycloak.common.util.KeycloakUriBuilder;
@@ -153,10 +154,10 @@ public class ServletOAuthClient extends KeycloakDeploymentDelegateOAuthClient {
 
     public static IDToken extractIdToken(String idToken) {
         if (idToken == null) return null;
-        JWSInput input = new JWSInput(idToken);
         try {
+            JWSInput input = new JWSInput(idToken);
             return input.readJsonContent(IDToken.class);
-        } catch (IOException e) {
+        } catch (JWSInputException e) {
             throw new RuntimeException(e);
         }
     }
diff --git a/model/api/src/main/java/org/keycloak/models/utils/CredentialValidation.java b/model/api/src/main/java/org/keycloak/models/utils/CredentialValidation.java
index af9b6b5..d3e4d4a 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/CredentialValidation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/CredentialValidation.java
@@ -1,6 +1,7 @@
 package org.keycloak.models.utils;
 
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.models.OTPPolicy;
 import org.keycloak.models.PasswordPolicy;
@@ -73,11 +74,11 @@ public class CredentialValidation {
     }
 
     public static boolean validPasswordToken(RealmModel realm, UserModel user, String encodedPasswordToken) {
-        JWSInput jws = new JWSInput(encodedPasswordToken);
-        if (!RSAProvider.verify(jws, realm.getPublicKey())) {
-            return false;
-        }
         try {
+            JWSInput jws = new JWSInput(encodedPasswordToken);
+            if (!RSAProvider.verify(jws, realm.getPublicKey())) {
+                return false;
+            }
             PasswordToken passwordToken = jws.readJsonContent(PasswordToken.class);
             if (!passwordToken.getRealm().equals(realm.getName())) {
                 return false;
@@ -89,7 +90,7 @@ public class CredentialValidation {
                 return false;
             }
             return true;
-        } catch (IOException e) {
+        } catch (JWSInputException e) {
             return false;
         }
     }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index 32a9a6d..304e6af 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -9,6 +9,7 @@ import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.jose.jws.JWSBuilder;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
@@ -195,44 +196,46 @@ public class TokenManager {
     }
 
     public RefreshToken verifyRefreshToken(RealmModel realm, String encodedRefreshToken) throws OAuthErrorException {
-        JWSInput jws = new JWSInput(encodedRefreshToken);
-        RefreshToken refreshToken = null;
         try {
+            JWSInput jws = new JWSInput(encodedRefreshToken);
+            RefreshToken refreshToken = null;
             if (!RSAProvider.verify(jws, realm.getPublicKey())) {
                 throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token");
             }
             refreshToken = jws.readJsonContent(RefreshToken.class);
-        } catch (Exception e) {
-            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", e);
-        }
-        if (refreshToken.getExpiration() != 0 && refreshToken.isExpired()) {
-            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh token expired");
-        }
 
-        if (refreshToken.getIssuedAt() < realm.getNotBefore()) {
-            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale refresh token");
+            if (refreshToken.getExpiration() != 0 && refreshToken.isExpired()) {
+                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh token expired");
+            }
+
+            if (refreshToken.getIssuedAt() < realm.getNotBefore()) {
+                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale refresh token");
+            }
+            return refreshToken;
+        } catch (JWSInputException e) {
+            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", e);
         }
-        return refreshToken;
     }
     public IDToken verifyIDToken(RealmModel realm, String encodedIDToken) throws OAuthErrorException {
-        JWSInput jws = new JWSInput(encodedIDToken);
-        IDToken idToken = null;
         try {
+            JWSInput jws = new JWSInput(encodedIDToken);
+            IDToken idToken;
             if (!RSAProvider.verify(jws, realm.getPublicKey())) {
                 throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid IDToken");
             }
             idToken = jws.readJsonContent(IDToken.class);
-        } catch (IOException e) {
-            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid IDToken", e);
-        }
-        if (idToken.isExpired()) {
-            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "IDToken expired");
-        }
 
-        if (idToken.getIssuedAt() < realm.getNotBefore()) {
-            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale IDToken");
+            if (idToken.isExpired()) {
+                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "IDToken expired");
+            }
+
+            if (idToken.getIssuedAt() < realm.getNotBefore()) {
+                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale IDToken");
+            }
+            return idToken;
+        } catch (JWSInputException e) {
+            throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid IDToken", e);
         }
-        return idToken;
     }
 
     public AccessToken createClientAccessToken(KeycloakSession session, Set<RoleModel> requestedRoles, RealmModel realm, ClientModel client, UserModel user, UserSessionModel userSession, ClientSessionModel clientSession) {
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java
index 241bcff..4d54d5f 100644
--- a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java
@@ -3,6 +3,7 @@ package org.keycloak.services.clientregistration;
 import org.keycloak.common.util.Time;
 import org.keycloak.jose.jws.JWSBuilder;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.models.ClientInitialAccessModel;
 import org.keycloak.models.ClientModel;
@@ -44,7 +45,7 @@ public class ClientRegistrationTokenUtils {
         JWSInput input;
         try {
             input = new JWSInput(token);
-        } catch (Exception e) {
+        } catch (JWSInputException e) {
             throw new ForbiddenException(e);
         }
 
@@ -55,7 +56,7 @@ public class ClientRegistrationTokenUtils {
         JsonWebToken jwt;
         try {
             jwt = input.readJsonContent(JsonWebToken.class);
-        } catch (IOException e) {
+        } catch (JWSInputException e) {
             throw new ForbiddenException(e);
         }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
index a7bead8..1ac5dba 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
@@ -9,6 +9,7 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.jboss.resteasy.spi.UnauthorizedException;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.models.AdminRoles;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
@@ -137,11 +138,11 @@ public class AdminRoot {
     protected AdminAuth authenticateRealmAdminRequest(HttpHeaders headers) {
         String tokenString = authManager.extractAuthorizationHeaderToken(headers);
         if (tokenString == null) throw new UnauthorizedException("Bearer");
-        JWSInput input = new JWSInput(tokenString);
         AccessToken token;
         try {
+            JWSInput input = new JWSInput(tokenString);
             token = input.readJsonContent(AccessToken.class);
-        } catch (IOException e) {
+        } catch (JWSInputException e) {
             throw new UnauthorizedException("Bearer token format error");
         }
         String realmName = token.getIssuer().substring(token.getIssuer().lastIndexOf('/') + 1);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
index e191871..1b6cbd6 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -38,6 +38,7 @@ import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.Event;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
@@ -806,26 +807,15 @@ public class AccessTokenTest {
         }
     }
 
-    private IDToken getIdToken(org.keycloak.representations.AccessTokenResponse tokenResponse) throws VerificationException {
+    private IDToken getIdToken(org.keycloak.representations.AccessTokenResponse tokenResponse) throws JWSInputException {
         JWSInput input = new JWSInput(tokenResponse.getIdToken());
-        IDToken idToken = null;
-        try {
-            idToken = input.readJsonContent(IDToken.class);
-        } catch (IOException e) {
-            throw new VerificationException();
-        }
-        return idToken;
+        return input.readJsonContent(IDToken.class);
     }
 
-    private AccessToken getAccessToken(org.keycloak.representations.AccessTokenResponse tokenResponse) throws VerificationException {
+    private AccessToken getAccessToken(org.keycloak.representations.AccessTokenResponse tokenResponse) throws JWSInputException {
         JWSInput input = new JWSInput(tokenResponse.getToken());
-        AccessToken idToken = null;
-        try {
-            idToken = input.readJsonContent(AccessToken.class);
-        } catch (IOException e) {
-            throw new VerificationException();
-        }
-        return idToken;
+        return input.readJsonContent(AccessToken.class);
+
     }
 
     protected Response executeGrantAccessTokenRequest(WebTarget grantTarget) {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
index 219fa4f..884d9f0 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
@@ -25,6 +25,7 @@ import org.keycloak.events.Errors;
 import org.keycloak.events.Event;
 import org.keycloak.events.EventType;
 import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.Constants;
 import org.keycloak.models.RealmModel;
@@ -645,7 +646,12 @@ public class OfflineTokenTest {
             StringBuilder response = new StringBuilder("<html><head><title>Offline token servlet</title></head><body><pre>");
             RefreshableKeycloakSecurityContext ctx = (RefreshableKeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
             String accessTokenPretty = JsonSerialization.writeValueAsPrettyString(ctx.getToken());
-            RefreshToken refreshToken = new JWSInput(ctx.getRefreshToken()).readJsonContent(RefreshToken.class);
+            RefreshToken refreshToken = null;
+            try {
+                refreshToken = new JWSInput(ctx.getRefreshToken()).readJsonContent(RefreshToken.class);
+            } catch (JWSInputException e) {
+                throw new IOException(e);
+            }
             String refreshTokenPretty = JsonSerialization.writeValueAsPrettyString(refreshToken);
 
             response = response.append(accessTokenPretty)
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
index 15f7f93..2373489 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
@@ -116,6 +116,14 @@ public class RefreshTokenTest {
     }
 
     @Test
+    public void invalidRefreshToken() throws Exception {
+        AccessTokenResponse response = oauth.doRefreshTokenRequest("invalid", "password");
+        Assert.assertEquals(400, response.getStatusCode());
+        Assert.assertEquals("invalid_grant", response.getError());
+        events.clear();
+    }
+
+    @Test
     public void refreshTokenRequest() throws Exception {
         oauth.doLogin("test-user@localhost", "password");