diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index f662037..e18b444 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -195,7 +195,7 @@ public class AuthenticationManager {
userSession.setState(UserSessionModel.State.LOGGING_OUT);
}
- logger.debugv("Logging out: {0} ({1})", user.getUsername(), userSession.getId());
+ logger.debugv("Logging out: {0} ({1}) offline: {2}", user.getUsername(), userSession.getId(), userSession.isOffline());
expireUserSessionCookie(session, userSession, realm, uriInfo, headers, connection);
final AuthenticationSessionManager asm = new AuthenticationSessionManager(session);
@@ -212,6 +212,12 @@ public class AuthenticationManager {
if (offlineSession) {
new UserSessionManager(session).revokeOfflineUserSession(userSession);
+
+ // Check if "online" session still exists and remove it too
+ UserSessionModel onlineUserSession = session.sessions().getUserSession(realm, userSession.getId());
+ if (onlineUserSession != null) {
+ session.sessions().removeUserSession(realm, onlineUserSession);
+ }
} else {
session.sessions().removeUserSession(realm, userSession);
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
index 1ba785a..8c0f9ef 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
@@ -65,6 +65,7 @@ import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
import static org.keycloak.testsuite.admin.ApiUtil.findRealmRoleByName;
import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername;
@@ -598,12 +599,17 @@ public class OfflineTokenTest extends AbstractKeycloakTest {
assertEquals(TokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
assertEquals(0, offlineToken.getExpiration());
- CloseableHttpResponse logoutResponse = oauth.doLogout(offlineTokenString, "secret1");
- assertEquals(204, logoutResponse.getStatusLine().getStatusCode());
+ try (CloseableHttpResponse logoutResponse = oauth.doLogout(offlineTokenString, "secret1")) {
+ assertEquals(204, logoutResponse.getStatusLine().getStatusCode());
+ }
- // after KEYCLOAK-6617 this will no longer work - will need to login again.
- oauth.openLoginForm();
+ events.expectLogout(offlineToken.getSessionState())
+ .client("offline-client")
+ .removeDetail(Details.REDIRECT_URI)
+ .assertEvent();
+ // Need to login again now
+ oauth.doLogin("test-user@localhost", "password");
String code2 = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
OAuthClient.AccessTokenResponse tokenResponse2 = oauth.doAccessTokenRequest(code2, "secret1");
@@ -612,8 +618,23 @@ public class OfflineTokenTest extends AbstractKeycloakTest {
String offlineTokenString2 = tokenResponse2.getRefreshToken();
RefreshToken offlineToken2 = oauth.verifyRefreshToken(offlineTokenString2);
+ loginEvent = events.expectLogin()
+ .client("offline-client")
+ .detail(Details.REDIRECT_URI, offlineClientAppUri)
+ .assertEvent();
+
+ codeId = loginEvent.getDetails().get(Details.CODE_ID);
+
+ events.expectCodeToToken(codeId, offlineToken2.getSessionState())
+ .client("offline-client")
+ .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
+ .assertEvent();
+
assertEquals(TokenUtil.TOKEN_TYPE_OFFLINE, offlineToken2.getType());
assertEquals(0, offlineToken2.getExpiration());
+
+ // Assert session changed
+ assertNotEquals(offlineToken.getSessionState(), offlineToken2.getSessionState());
}
}