KEYCLOAK-983 Fix login after reset-password
This commit is contained in:
parent
715482e371
commit
e7a792f922
9 changed files with 117 additions and 28 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public class UserSessionEntity {
|
|||
@Column(name="USER_SESSION_STATE")
|
||||
protected UserSessionModel.State state;
|
||||
|
||||
@OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true, mappedBy="session")
|
||||
@OneToMany(mappedBy="session")
|
||||
protected Collection<ClientSessionEntity> clientSessions = new ArrayList<ClientSessionEntity>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true, mappedBy="userSession")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -137,10 +138,21 @@ 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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
@ -151,6 +152,36 @@ public class ResetPasswordTest {
|
|||
Assert.assertEquals("Unknown code, please login again through your application.", errorPage.getError());
|
||||
}
|
||||
|
||||
@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");
|
||||
|
|
Loading…
Reference in a new issue