keycloak-aplcache
Changes
model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java 23(+15 -8)
model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java 22(+18 -4)
model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/UserSessionEntity.java 2(+1 -1)
model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/JpaUserSessionProvider.java 3(+3 -0)
model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java 15(+11 -4)
Details
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java
index 2c6addc..645a76f 100644
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java
@@ -53,17 +53,24 @@ public class ClientSessionAdapter implements ClientSessionModel {
@Override
public void setUserSession(UserSessionModel userSession) {
- if (entity.getUserSession() != null) {
- if (entity.getUserSession().equals(userSession.getId())) {
- return;
- } else {
- provider.dettachSession(userSession, this);
+ if (userSession == null) {
+ if (entity.getUserSession() != null) {
+ provider.dettachSession(getUserSession(), this);
}
+ entity.setUserSession(null);
} else {
- provider.attachSession(userSession, this);
- }
+ if (entity.getUserSession() != null) {
+ if (entity.getUserSession().equals(userSession.getId())) {
+ return;
+ } else {
+ provider.dettachSession(userSession, this);
+ }
+ } else {
+ provider.attachSession(userSession, this);
+ }
- entity.setUserSession(userSession.getId());
+ entity.setUserSession(userSession.getId());
+ }
update();
}
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 e05130c..18b0332 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
@@ -87,10 +87,17 @@ public class ClientSessionAdapter implements ClientSessionModel {
@Override
public void setUserSession(UserSessionModel userSession) {
- UserSessionAdapter adapter = (UserSessionAdapter)userSession;
- UserSessionEntity userSessionEntity = adapter.getEntity();
- entity.setSession(userSessionEntity);
- userSessionEntity.getClientSessions().add(entity);
+ if (userSession == null) {
+ if (entity.getSession() != null) {
+ entity.getSession().getClientSessions().remove(entity);
+ }
+ entity.setSession(null);
+ } else {
+ UserSessionAdapter adapter = (UserSessionAdapter) userSession;
+ UserSessionEntity userSessionEntity = adapter.getEntity();
+ entity.setSession(userSessionEntity);
+ userSessionEntity.getClientSessions().add(entity);
+ }
}
@Override
@@ -109,6 +116,13 @@ public class ClientSessionAdapter implements ClientSessionModel {
entity.getRoles().add(roleEntity);
}
+ } else {
+ if (entity.getRoles() != null) {
+ for (ClientSessionRoleEntity r : entity.getRoles()) {
+ em.remove(r);
+ }
+ entity.getRoles().clear();
+ }
}
}
diff --git a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/UserSessionEntity.java b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/UserSessionEntity.java
index e807861..97aa742 100755
--- a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/UserSessionEntity.java
+++ b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/UserSessionEntity.java
@@ -54,7 +54,7 @@ public class UserSessionEntity {
@Column(name="LAST_SESSION_REFRESH")
protected int lastSessionRefresh;
- @OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true, mappedBy="session")
+ @OneToMany(mappedBy="session")
protected Collection<ClientSessionEntity> clientSessions = new ArrayList<ClientSessionEntity>();
public String getId() {
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 6708a2d..760e368 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
@@ -155,6 +155,9 @@ public class JpaUserSessionProvider implements UserSessionProvider {
public void removeUserSession(RealmModel realm, UserSessionModel session) {
UserSessionEntity entity = em.find(UserSessionEntity.class, session.getId());
if (entity != null) {
+ for (ClientSessionEntity c : entity.getClientSessions()) {
+ em.remove(c);
+ }
em.remove(entity);
}
}
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 1328171..9981fb7 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
@@ -52,10 +52,17 @@ public class ClientSessionAdapter implements ClientSessionModel {
@Override
public void setUserSession(UserSessionModel userSession) {
- UserSessionAdapter adapter = (UserSessionAdapter)userSession;
- UserSessionEntity userSessionEntity = adapter.getEntity();
- entity.setSession(userSessionEntity);
- userSessionEntity.getClientSessions().add(entity);
+ if (userSession == null) {
+ if (entity.getSession() != null) {
+ entity.getSession().getClientSessions().remove(entity);
+ }
+ entity.setSession(null);
+ } else {
+ UserSessionAdapter adapter = (UserSessionAdapter) userSession;
+ UserSessionEntity userSessionEntity = adapter.getEntity();
+ entity.setSession(userSessionEntity);
+ userSessionEntity.getClientSessions().add(entity);
+ }
}
@Override
diff --git a/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java b/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java
index 92773f8..2ab8630 100755
--- a/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java
+++ b/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java
@@ -55,11 +55,19 @@ public class ClientSessionAdapter extends AbstractMongoAdapter<MongoClientSessio
@Override
public void setUserSession(UserSessionModel userSession) {
- MongoUserSessionEntity userSessionEntity = provider.getUserSessionEntity(realm, userSession.getId());
- entity.setSessionId(userSessionEntity.getId());
- updateMongoEntity();
+ if (userSession == null) {
+ if (entity.getSessionId() != null) {
+ MongoUserSessionEntity userSessionEntity = provider.getUserSessionEntity(realm, entity.getSessionId());
+ provider.getMongoStore().pullItemFromList(userSessionEntity, "clientSessions", entity.getSessionId(), invocationContext);
+ }
+ entity.setSessionId(null);
+ } else {
+ MongoUserSessionEntity userSessionEntity = provider.getUserSessionEntity(realm, userSession.getId());
+ entity.setSessionId(userSessionEntity.getId());
+ updateMongoEntity();
- provider.getMongoStore().pushItemToList(userSessionEntity, "clientSessions", entity.getId(), true, invocationContext);
+ provider.getMongoStore().pushItemToList(userSessionEntity, "clientSessions", entity.getId(), true, invocationContext);
+ }
}
@Override
@@ -70,9 +78,13 @@ public class ClientSessionAdapter extends AbstractMongoAdapter<MongoClientSessio
@Override
public void setRoles(Set<String> roles) {
- List<String> list = new LinkedList<String>();
- list.addAll(roles);
- entity.setRoles(list);
+ if (roles == null) {
+ entity.setRoles(null);
+ } else {
+ List<String> list = new LinkedList<String>();
+ list.addAll(roles);
+ entity.setRoles(list);
+ }
updateMongoEntity();
}
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 7dad225..f6911dc 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -17,6 +17,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
@@ -136,11 +137,22 @@ public class TokenManager {
requestedRoles.add(r.getId());
}
clientSession.setRoles(requestedRoles);
+ }
+
+ public static void dettachClientSession(UserSessionProvider sessions, RealmModel realm, ClientSessionModel clientSession) {
+ UserSessionModel userSession = clientSession.getUserSession();
+ if (userSession == null) {
+ return;
+ }
+ clientSession.setUserSession(null);
+ clientSession.setRoles(null);
+ if (userSession.getClientSessions().isEmpty()) {
+ sessions.removeUserSession(realm, userSession);
+ }
}
-
public static Set<RoleModel> getAccess(String scopeParam, ClientModel client, UserModel user) {
// todo scopeParam is ignored until we figure out a scheme that fits with openid connect
Set<RoleModel> requestedRoles = new HashSet<RoleModel>();
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 84f7cdb..33988da 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -200,7 +200,10 @@ public class LoginActionsService {
ClientSessionCode clientSessionCode = checks.clientCode;
ClientSessionModel clientSession = clientSessionCode.getClientSession();
-
+ if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD)) {
+ TokenManager.dettachClientSession(session.sessions(), realm, clientSession);
+ clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
+ }
LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo)
.setClientSessionCode(clientSessionCode.getCode());
@@ -267,7 +270,7 @@ public class LoginActionsService {
return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown code, please login again through your application.");
}
ClientSessionModel clientSession = clientCode.getClientSession();
- if (!(clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE) || clientCode.isValid(ClientSessionModel.Action.RECOVER_PASSWORD))) {
+ if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE) || clientSession.getUserSession() != null) {
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE);
event.client(clientSession.getClient()).error(Errors.INVALID_CODE);
return Flows.forms(this.session, realm, clientSession.getClient(), uriInfo).setError(Messages.INVALID_USER)
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 07b24d7..6ac7860 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
@@ -27,6 +27,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
+import org.keycloak.events.Event;
import org.keycloak.events.EventType;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
@@ -152,6 +153,36 @@ public class ResetPasswordTest {
}
@Test
+ public void resetPasswordCancelChangeUser() throws IOException, MessagingException {
+ loginPage.open();
+ loginPage.resetPassword();
+
+ resetPasswordPage.assertCurrent();
+
+ resetPasswordPage.changePassword("test-user@localhost");
+
+ resetPasswordPage.assertCurrent();
+
+ events.expectRequiredAction(EventType.SEND_RESET_PASSWORD).detail(Details.USERNAME, "test-user@localhost").detail(Details.EMAIL, "test-user@localhost").assertEvent().getSessionId();
+
+ resetPasswordPage.backToLogin();
+
+ Assert.assertTrue(loginPage.isCurrent());
+
+ loginPage.login("login@test.com", "password");
+
+ Event loginEvent = events.expectLogin().user(userId).detail(Details.USERNAME, "login@test.com").assertEvent();
+
+ String code = oauth.getCurrentQuery().get("code");
+ OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password");
+
+ Assert.assertEquals(200, tokenResponse.getStatusCode());
+ Assert.assertEquals(userId, oauth.verifyToken(tokenResponse.getAccessToken()).getSubject());
+
+ events.expectCodeToToken(loginEvent.getDetails().get(Details.CODE_ID), loginEvent.getSessionId()).user(userId).assertEvent();
+ }
+
+ @Test
public void resetPasswordByEmail() throws IOException, MessagingException {
resetPassword("login@test.com");
}