cleanup client sessions
This commit is contained in:
parent
39e0023a5f
commit
d7b818cba2
17 changed files with 136 additions and 16 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -135,4 +135,6 @@ public class ClientSessionEntity extends SessionEntity {
|
|||
public void setUserSessionNotes(Map<String, String> userSessionNotes) {
|
||||
this.userSessionNotes = userSessionNotes;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
17
model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java
Normal file → Executable file
17
model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java
Normal file → Executable file
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -47,6 +48,13 @@ public class JpaUserSessionProvider implements UserSessionProvider {
|
|||
return new ClientSessionAdapter(session, em, realm, entity);
|
||||
}
|
||||
|
||||
@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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,9 @@ public class ClientSessionAdapter implements ClientSessionModel {
|
|||
return session.realms().getRealm(entity.getRealmId());
|
||||
}
|
||||
|
||||
|
||||
public ClientSessionEntity getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientModel getClient() {
|
||||
|
|
|
@ -58,6 +58,17 @@ public class MemUserSessionProvider implements UserSessionProvider {
|
|||
return new ClientSessionAdapter(session, this, realm, entity);
|
||||
}
|
||||
|
||||
@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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,19 @@ public class MongoUserSessionProvider implements UserSessionProvider {
|
|||
return new ClientSessionAdapter(session, this, realm, entity, invocationContext);
|
||||
}
|
||||
|
||||
@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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in a new issue