use of org.keycloak.services.managers.UserSessionManager in project keycloak by keycloak.
the class TokenRevocationEndpoint method revokeClient.
private void revokeClient() {
session.users().revokeConsentForClient(realm, user.getId(), client.getId());
if (TokenUtil.TOKEN_TYPE_OFFLINE.equals(token.getType())) {
new UserSessionManager(session).revokeOfflineToken(user, client);
}
session.sessions().getUserSessionsStream(realm, user).map(userSession -> userSession.getAuthenticatedClientSessionByClient(client.getId())).filter(Objects::nonNull).collect(// collect to avoid concurrent modification as dettachClientSession removes the user sessions.
Collectors.toList()).forEach(clientSession -> {
UserSessionModel userSession = clientSession.getUserSession();
TokenManager.dettachClientSession(clientSession);
if (userSession != null) {
// TODO: Might need optimization to prevent loading client sessions from cache in getAuthenticatedClientSessions()
if (userSession.getAuthenticatedClientSessions().isEmpty()) {
session.sessions().removeUserSession(realm, userSession);
}
}
});
}
use of org.keycloak.services.managers.UserSessionManager in project keycloak by keycloak.
the class UserResource method getOfflineSessions.
/**
* Get offline sessions associated with the user and client
*
* @return
*/
@Path("offline-sessions/{clientUuid}")
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public Stream<UserSessionRepresentation> getOfflineSessions(@PathParam("clientUuid") final String clientUuid) {
auth.users().requireView(user);
ClientModel client = realm.getClientById(clientUuid);
if (client == null) {
throw new NotFoundException("Client not found");
}
return new UserSessionManager(session).findOfflineSessionsStream(realm, user).map(session -> toUserSessionRepresentation(session, clientUuid)).filter(Objects::nonNull);
}
use of org.keycloak.services.managers.UserSessionManager in project keycloak by keycloak.
the class TokenManager method validateTokenReuseForIntrospection.
private boolean validateTokenReuseForIntrospection(KeycloakSession session, RealmModel realm, AccessToken token) {
UserSessionModel userSession = null;
if (token.getType().equals(TokenUtil.TOKEN_TYPE_REFRESH)) {
userSession = session.sessions().getUserSession(realm, token.getSessionState());
} else {
UserSessionManager sessionManager = new UserSessionManager(session);
userSession = sessionManager.findOfflineUserSession(realm, token.getSessionState());
}
ClientModel client = realm.getClientByClientId(token.getIssuedFor());
AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
try {
validateTokenReuse(session, realm, token, clientSession, false);
return true;
} catch (OAuthErrorException e) {
return false;
}
}
use of org.keycloak.services.managers.UserSessionManager in project keycloak by keycloak.
the class TokenManager method validateToken.
public TokenValidation validateToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, RefreshToken oldToken, HttpHeaders headers) throws OAuthErrorException {
UserSessionModel userSession = null;
boolean offline = TokenUtil.TOKEN_TYPE_OFFLINE.equals(oldToken.getType());
if (offline) {
UserSessionManager sessionManager = new UserSessionManager(session);
userSession = sessionManager.findOfflineUserSession(realm, oldToken.getSessionState());
if (userSession != null) {
// Revoke timeouted offline userSession
if (!AuthenticationManager.isOfflineSessionValid(realm, userSession)) {
sessionManager.revokeOfflineUserSession(userSession);
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Offline session not active", "Offline session not active");
}
} else {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Offline user session not found", "Offline user session not found");
}
} else {
// Find userSession regularly for online tokens
userSession = session.sessions().getUserSession(realm, oldToken.getSessionState());
if (!AuthenticationManager.isSessionValid(realm, userSession)) {
AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active");
}
}
UserModel user = userSession.getUser();
if (user == null) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown user");
}
if (!user.isEnabled()) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "User disabled", "User disabled");
}
if (oldToken.isIssuedBeforeSessionStart(userSession.getStarted())) {
logger.debug("Refresh toked issued before the user session started");
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh toked issued before the user session started");
}
ClientModel client = session.getContext().getClient();
AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
// Can theoretically happen in cross-dc environment. Try to see if userSession with our client is available in remoteCache
if (clientSession == null) {
userSession = new UserSessionCrossDCManager(session).getUserSessionWithClient(realm, userSession.getId(), offline, client.getId());
if (userSession != null) {
clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
} else {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session doesn't have required client", "Session doesn't have required client");
}
}
if (oldToken.isIssuedBeforeSessionStart(clientSession.getStarted())) {
logger.debug("Refresh toked issued before the client session started");
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh toked issued before the client session started");
}
if (!client.getClientId().equals(oldToken.getIssuedFor())) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients");
}
try {
TokenVerifier.createWithoutSignature(oldToken).withChecks(NotBeforeCheck.forModel(client), NotBeforeCheck.forModel(session, realm, user)).verify();
} catch (VerificationException e) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token");
}
// Setup clientScopes from refresh token to the context
String oldTokenScope = oldToken.getScope();
// Case when offline token is migrated from previous version
if (oldTokenScope == null && userSession.isOffline()) {
logger.debugf("Migrating offline token of user '%s' for client '%s' of realm '%s'", user.getUsername(), client.getClientId(), realm.getName());
MigrationUtils.migrateOldOfflineToken(session, realm, client, user);
oldTokenScope = OAuth2Constants.OFFLINE_ACCESS;
}
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(clientSession, oldTokenScope, session);
// Check user didn't revoke granted consent
if (!verifyConsentStillAvailable(session, user, client, clientSessionCtx.getClientScopesStream())) {
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user");
}
clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, oldToken.getNonce());
// recreate token.
AccessToken newToken = createClientAccessToken(session, realm, client, user, userSession, clientSessionCtx);
return new TokenValidation(user, userSession, clientSessionCtx, newToken);
}
use of org.keycloak.services.managers.UserSessionManager in project keycloak by keycloak.
the class UserSessionProviderOfflineTest method testOfflineSessionsCrud.
@Test
@ModelTest
public void testOfflineSessionsCrud(KeycloakSession session) {
Map<String, Set<String>> offlineSessions = new HashMap<>();
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionCrud) -> {
// Create some online sessions in infinispan
reloadState(sessionCrud);
createSessions(sessionCrud);
});
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionCrud2) -> {
currentSession = sessionCrud2;
realm = currentSession.realms().getRealm("test");
sessionManager = new UserSessionManager(currentSession);
// Key is userSession ID, values are client UUIDS
// Persist 3 created userSessions and clientSessions as offline
ClientModel testApp = realm.getClientByClientId("test-app");
currentSession.sessions().getUserSessionsStream(realm, testApp).collect(Collectors.toList()).forEach(userSession -> offlineSessions.put(userSession.getId(), createOfflineSessionIncludeClientSessions(currentSession, userSession)));
});
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionCrud3) -> {
currentSession = sessionCrud3;
realm = currentSession.realms().getRealm("test");
sessionManager = new UserSessionManager(currentSession);
// Assert all previously saved offline sessions found
for (Map.Entry<String, Set<String>> entry : offlineSessions.entrySet()) {
UserSessionModel offlineSession = sessionManager.findOfflineUserSession(realm, entry.getKey());
Assert.assertNotNull(offlineSession);
Assert.assertEquals(offlineSession.getAuthenticatedClientSessions().keySet(), entry.getValue());
}
// Find clients with offline token
UserModel user1 = currentSession.users().getUserByUsername(realm, "user1");
Set<ClientModel> clients = sessionManager.findClientsWithOfflineToken(realm, user1);
Assert.assertEquals(clients.size(), 2);
for (ClientModel client : clients) {
Assert.assertTrue(client.getClientId().equals("test-app") || client.getClientId().equals("third-party"));
}
UserModel user2 = currentSession.users().getUserByUsername(realm, "user2");
clients = sessionManager.findClientsWithOfflineToken(realm, user2);
Assert.assertEquals(clients.size(), 1);
Assert.assertEquals("test-app", clients.iterator().next().getClientId());
// Test count
ClientModel testApp = realm.getClientByClientId("test-app");
ClientModel thirdparty = realm.getClientByClientId("third-party");
Assert.assertEquals(3, currentSession.sessions().getOfflineSessionsCount(realm, testApp));
Assert.assertEquals(1, currentSession.sessions().getOfflineSessionsCount(realm, thirdparty));
// Revoke "test-app" for user1
sessionManager.revokeOfflineToken(user1, testApp);
});
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionCrud4) -> {
currentSession = sessionCrud4;
realm = currentSession.realms().getRealm("test");
sessionManager = new UserSessionManager(currentSession);
// Assert userSession revoked
ClientModel thirdparty = realm.getClientByClientId("third-party");
List<UserSessionModel> thirdpartySessions = currentSession.sessions().getOfflineUserSessionsStream(realm, thirdparty, 0, 10).collect(Collectors.toList());
Assert.assertEquals(1, thirdpartySessions.size());
Assert.assertEquals("127.0.0.1", thirdpartySessions.get(0).getIpAddress());
Assert.assertEquals("user1", thirdpartySessions.get(0).getUser().getUsername());
UserModel user1 = currentSession.users().getUserByUsername(realm, "user1");
UserModel user2 = currentSession.users().getUserByUsername(realm, "user2");
Set<ClientModel> clients = sessionManager.findClientsWithOfflineToken(realm, user1);
Assert.assertEquals(1, clients.size());
Assert.assertEquals("third-party", clients.iterator().next().getClientId());
clients = sessionManager.findClientsWithOfflineToken(realm, user2);
Assert.assertEquals(1, clients.size());
Assert.assertEquals("test-app", clients.iterator().next().getClientId());
// Revoke the second currentSession for user1 too.
sessionManager.revokeOfflineToken(user1, thirdparty);
});
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionCrud5) -> {
currentSession = sessionCrud5;
realm = currentSession.realms().getRealm("test");
sessionManager = new UserSessionManager(currentSession);
ClientModel testApp = realm.getClientByClientId("test-app");
ClientModel thirdparty = realm.getClientByClientId("third-party");
// Accurate count now. All sessions of user1 cleared
Assert.assertEquals(1, currentSession.sessions().getOfflineSessionsCount(realm, testApp));
Assert.assertEquals(0, currentSession.sessions().getOfflineSessionsCount(realm, thirdparty));
List<UserSessionModel> testAppSessions = currentSession.sessions().getOfflineUserSessionsStream(realm, testApp, 0, 10).collect(Collectors.toList());
Assert.assertEquals(1, testAppSessions.size());
Assert.assertEquals("127.0.0.3", testAppSessions.get(0).getIpAddress());
Assert.assertEquals("user2", testAppSessions.get(0).getUser().getUsername());
UserModel user1 = currentSession.users().getUserByUsername(realm, "user1");
Set<ClientModel> clients = sessionManager.findClientsWithOfflineToken(realm, user1);
Assert.assertEquals(0, clients.size());
});
}
Aggregations