keycloak-aplcache

Changes

Details

diff --git a/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java b/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java
index 3a64206..89f8cee 100755
--- a/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java
+++ b/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java
@@ -29,6 +29,7 @@ public interface UserSessionProvider extends Provider {
     void removeUserSessions(RealmModel realm, UserModel user);
     void removeExpiredUserSessions(RealmModel realm);
     void removeUserSessions(RealmModel realm);
+    void removeClientSession(RealmModel realm, ClientSessionModel clientSession);
 
     UsernameLoginFailureModel getUserLoginFailure(RealmModel realm, String username);
     UsernameLoginFailureModel addUserLoginFailure(RealmModel realm, String username);
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientSessionEntity.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientSessionEntity.java
index 3cb6614..a00e805 100755
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientSessionEntity.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientSessionEntity.java
@@ -135,4 +135,6 @@ public class ClientSessionEntity extends SessionEntity {
     public void setUserSessionNotes(Map<String, String> userSessionNotes) {
         this.userSessionNotes = userSessionNotes;
     }
+
+
 }
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java
old mode 100644
new mode 100755
index 5d6fc3c..62e1861
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java
@@ -26,4 +26,21 @@ public class SessionEntity implements Serializable {
     public void setRealm(String realm) {
         this.realm = realm;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SessionEntity)) return false;
+
+        SessionEntity that = (SessionEntity) o;
+
+        if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id != null ? id.hashCode() : 0;
+    }
 }
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
index e7ff079..2275a98 100755
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
@@ -334,6 +334,21 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
         }
     }
 
+    @Override
+    public void removeClientSession(RealmModel realm, ClientSessionModel clientSession) {
+        UserSessionModel userSession = clientSession.getUserSession();
+        if (userSession != null)  {
+            UserSessionEntity entity = ((UserSessionAdapter) userSession).getEntity();
+            if (entity.getClientSessions() != null) {
+                entity.getClientSessions().remove(clientSession.getId());
+
+            }
+            tx.replace(sessionCache, entity.getId(), entity);
+        }
+        tx.remove(sessionCache, clientSession.getId());
+    }
+
+
     void dettachSession(UserSessionModel userSession, ClientSessionModel clientSession) {
         UserSessionEntity entity = ((UserSessionAdapter) userSession).getEntity();
         String clientSessionId = clientSession.getId();
@@ -359,6 +374,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
         }
     }
 
+
     InfinispanKeycloakTransaction getTx() {
         return tx;
     }
diff --git a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java
index e8498e9..a6b3016 100755
--- a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java
+++ b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java
@@ -128,6 +128,10 @@ public class ClientSessionAdapter implements ClientSessionModel {
         return realm.getClientById(entity.getClientId());
     }
 
+    public ClientSessionEntity getEntity() {
+        return entity;
+    }
+
     @Override
     public void setUserSession(UserSessionModel userSession) {
         if (userSession == null) {
diff --git a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/ClientSessionEntity.java b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/ClientSessionEntity.java
index 300c45a..5789ea8 100755
--- a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/ClientSessionEntity.java
+++ b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/ClientSessionEntity.java
@@ -186,4 +186,21 @@ public class ClientSessionEntity {
     public void setUserSessionNotes(Collection<ClientUserSessionNoteEntity> userSessionNotes) {
         this.userSessionNotes = userSessionNotes;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof ClientSessionEntity)) return false;
+
+        ClientSessionEntity that = (ClientSessionEntity) o;
+
+        if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id != null ? id.hashCode() : 0;
+    }
 }
diff --git a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/JpaUserSessionProvider.java b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/JpaUserSessionProvider.java
index 23086d9..8614ec0 100755
--- a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/JpaUserSessionProvider.java
+++ b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/JpaUserSessionProvider.java
@@ -18,6 +18,7 @@ import org.keycloak.util.Time;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -48,6 +49,13 @@ public class JpaUserSessionProvider implements UserSessionProvider {
     }
 
     @Override
+    public void removeClientSession(RealmModel realm, ClientSessionModel clientSession) {
+        ClientSessionEntity clientSessionEntity = ((ClientSessionAdapter)clientSession).getEntity();
+        em.remove(clientSessionEntity);
+        em.flush();
+   }
+
+    @Override
     public ClientSessionModel getClientSession(RealmModel realm, String id) {
         ClientSessionEntity clientSession = em.find(ClientSessionEntity.class, id);
         if (clientSession != null && clientSession.getRealmId().equals(realm.getId())) {
diff --git a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java
index f9e52d0..3053a9d 100755
--- a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java
+++ b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java
@@ -39,7 +39,9 @@ public class ClientSessionAdapter implements ClientSessionModel {
         return session.realms().getRealm(entity.getRealmId());
     }
 
-
+    public ClientSessionEntity getEntity() {
+        return entity;
+    }
 
     @Override
     public ClientModel getClient() {
diff --git a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/entities/ClientSessionEntity.java b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/entities/ClientSessionEntity.java
index da5e050..7c6fb22 100755
--- a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/entities/ClientSessionEntity.java
+++ b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/entities/ClientSessionEntity.java
@@ -132,4 +132,21 @@ public class ClientSessionEntity {
     public Map<String, String> getUserSessionNotes() {
         return userSessionNotes;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof ClientSessionEntity)) return false;
+
+        ClientSessionEntity that = (ClientSessionEntity) o;
+
+        if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id != null ? id.hashCode() : 0;
+    }
 }
diff --git a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/MemUserSessionProvider.java b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/MemUserSessionProvider.java
index 67a2180..ac6655f 100755
--- a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/MemUserSessionProvider.java
+++ b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/MemUserSessionProvider.java
@@ -59,6 +59,17 @@ public class MemUserSessionProvider implements UserSessionProvider {
     }
 
     @Override
+    public void removeClientSession(RealmModel realm, ClientSessionModel clientSession) {
+        ClientSessionEntity entity = ((ClientSessionAdapter)clientSession).getEntity();
+        UserSessionModel userSession = clientSession.getUserSession();
+        if (userSession != null) {
+            UserSessionEntity userSessionEntity = ((UserSessionAdapter)userSession).getEntity();
+            userSessionEntity.getClientSessions().remove(entity);
+        }
+        clientSessions.remove(clientSession.getId());
+    }
+
+    @Override
     public ClientSessionModel getClientSession(RealmModel realm, String id) {
         ClientSessionEntity entity = clientSessions.get(id);
         return entity != null ? new ClientSessionAdapter(session, this, realm, entity) : null;
diff --git a/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/MongoUserSessionProvider.java b/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/MongoUserSessionProvider.java
index 848fdeb..82045fd 100755
--- a/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/MongoUserSessionProvider.java
+++ b/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/MongoUserSessionProvider.java
@@ -56,6 +56,19 @@ public class MongoUserSessionProvider implements UserSessionProvider {
     }
 
     @Override
+    public void removeClientSession(RealmModel realm, ClientSessionModel clientSession) {
+        MongoClientSessionEntity entity = ((ClientSessionAdapter)clientSession).getMongoEntity();
+        if (entity.getSessionId() != null) {
+            MongoUserSessionEntity userSessionEntity = getUserSessionEntity(realm, entity.getSessionId());
+            getMongoStore().pullItemFromList(userSessionEntity, "clientSessions", entity.getSessionId(), invocationContext);
+
+        }
+
+        mongoStore.removeEntity(entity, invocationContext);
+
+    }
+
+    @Override
     public ClientSessionModel getClientSession(RealmModel realm, String id) {
         MongoClientSessionEntity entity = getClientSessionEntity(id);
         if (entity == null) return null;
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index 9db48d1..d5630bd 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -134,12 +134,9 @@ public class SamlProtocol implements LoginProtocol {
 
     @Override
     public Response cancelLogin(ClientSessionModel clientSession) {
-        return getErrorResponse(clientSession, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
-    }
-
-    @Override
-    public Response invalidSessionError(ClientSessionModel clientSession) {
-        return getErrorResponse(clientSession, JBossSAMLURIConstants.STATUS_AUTHNFAILED.get());
+        Response error = getErrorResponse(clientSession, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
+        session.sessions().removeClientSession(realm, clientSession);
+        return error;
     }
 
     protected String getResponseIssuer(RealmModel realm) {
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index fce95a2..aa0a0cf 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -459,7 +459,8 @@ public class AuthenticationProcessor {
         return authenticationComplete();
     }
 
-    protected void resetFlow() {
+    public static  void resetFlow(ClientSessionModel clientSession) {
+        clientSession.setAuthenticatedUser(null);
         clientSession.clearExecutionStatus();
         clientSession.clearUserSessionNotes();
         clientSession.removeNote(CURRENT_AUTHENTICATION_EXECUTION);
@@ -471,14 +472,14 @@ public class AuthenticationProcessor {
         if (!execution.equals(current)) {
             logger.debug("Current execution does not equal executed execution.  Might be a page refresh");
             logFailure();
-            resetFlow();
+            resetFlow(clientSession);
             return authenticate();
         }
         AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
         if (model == null) {
             logger.debug("Cannot find execution, reseting flow");
             logFailure();
-            resetFlow();
+            resetFlow(clientSession);
             return authenticate();
         }
         event.event(EventType.LOGIN);
diff --git a/services/src/main/java/org/keycloak/protocol/LoginProtocol.java b/services/src/main/java/org/keycloak/protocol/LoginProtocol.java
index be1711b..51676f3 100755
--- a/services/src/main/java/org/keycloak/protocol/LoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/LoginProtocol.java
@@ -28,7 +28,6 @@ public interface LoginProtocol extends Provider {
     LoginProtocol setEventBuilder(EventBuilder event);
 
     Response cancelLogin(ClientSessionModel clientSession);
-    Response invalidSessionError(ClientSessionModel clientSession);
     Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode);
     Response consentDenied(ClientSessionModel clientSession);
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
index 4ef8544..c002335 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
@@ -122,6 +122,7 @@ public class OIDCLoginProtocol implements LoginProtocol {
         if (state != null) {
             redirectUri.queryParam(OAuth2Constants.STATE, state);
         }
+        session.sessions().removeClientSession(realm, clientSession);
         return Response.status(302).location(redirectUri.build()).build();
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index cca6bb0..d921cf1 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -182,7 +182,15 @@ public class LoginActionsService {
             } else if (!(clientCode.isActionActive(requiredAction) || clientCode.isActionActive(alternativeRequiredAction))) {
                 event.client(clientCode.getClientSession().getClient());
                 event.error(Errors.EXPIRED_CODE);
-                response = ErrorPage.error(session, Messages.EXPIRED_CODE);
+                if (clientCode.getClientSession().getAction().equals(ClientSessionModel.Action.AUTHENTICATE.name())) {
+                    AuthenticationProcessor.resetFlow(clientCode.getClientSession());
+                    response = processAuthentication(null, clientCode.getClientSession());
+                } else {
+                    if (clientCode.getClientSession().getUserSession() == null) {
+                        session.sessions().removeClientSession(realm, clientCode.getClientSession());
+                    }
+                    response = ErrorPage.error(session, Messages.EXPIRED_CODE);
+                }
                 return false;
             } else {
                 return true;
@@ -207,21 +215,26 @@ public class LoginActionsService {
                 return false;
             }
             ClientSessionModel clientSession = clientCode.getClientSession();
+            if (clientSession == null) {
+                event.error(Errors.INVALID_CODE);
+                response = ErrorPage.error(session, Messages.INVALID_CODE);
+                return false;
+            }
             event.detail(Details.CODE_ID, clientSession.getId());
             ClientModel client = clientSession.getClient();
             if (client == null) {
                 event.error(Errors.CLIENT_NOT_FOUND);
                 response = ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
+                session.sessions().removeClientSession(realm, clientSession);
                 return false;
             }
-            session.getContext().setClient(client);
-
             if (!client.isEnabled()) {
                 event.error(Errors.CLIENT_NOT_FOUND);
                 response = ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
+                session.sessions().removeClientSession(realm, clientSession);
                 return false;
             }
-            session.getContext().setClient(clientCode.getClientSession().getClient());
+            session.getContext().setClient(client);
             return true;
         }
     }
@@ -239,7 +252,7 @@ public class LoginActionsService {
                                  @QueryParam("execution") String execution) {
         event.event(EventType.LOGIN);
         Checks checks = new Checks();
-        if (!checks.check(code)) {
+        if (!checks.check(code, ClientSessionModel.Action.AUTHENTICATE.name(), ClientSessionModel.Action.RECOVER_PASSWORD.name())) {
             return checks.response;
         }
         event.detail(Details.CODE_ID, code);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
index 17ca887..e3926ef 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
@@ -137,6 +137,7 @@ public class ResetPasswordTest {
 
         events.expectRequiredAction(EventType.SEND_RESET_PASSWORD).user(userId).detail(Details.USERNAME, "login-test").detail(Details.EMAIL, "login@test.com").assertEvent().getSessionId();
 
+        String src = driver.getPageSource();
         resetPasswordPage.backToLogin();
 
         assertTrue(loginPage.isCurrent());