All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.arbeitsagentur.opdt.keycloak.cassandra.userSession.persistence.CassandraUserSessionRepository Maven / Gradle / Ivy

/*
 * Copyright 2022 IT-Systemhaus der Bundesagentur fuer Arbeit
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.arbeitsagentur.opdt.keycloak.cassandra.userSession.persistence;

import de.arbeitsagentur.opdt.keycloak.cassandra.StreamExtensions;
import de.arbeitsagentur.opdt.keycloak.cassandra.userSession.persistence.entities.AttributeToUserSessionMapping;
import de.arbeitsagentur.opdt.keycloak.cassandra.userSession.persistence.entities.AuthenticatedClientSessionValue;
import de.arbeitsagentur.opdt.keycloak.cassandra.userSession.persistence.entities.UserSession;
import de.arbeitsagentur.opdt.keycloak.cassandra.userSession.persistence.entities.UserSessionToAttributeMapping;
import lombok.RequiredArgsConstructor;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.Time;
import de.arbeitsagentur.opdt.keycloak.mapstorage.common.TimeAdapter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static org.keycloak.models.UserSessionModel.CORRESPONDING_SESSION_ID;
import static org.keycloak.models.UserSessionModel.SessionPersistenceState.PERSISTENT;

@RequiredArgsConstructor
public class CassandraUserSessionRepository implements UserSessionRepository {
    private static final String CLIENT_IDS = "clientIds";
    private static final String USER_ID = "userId";
    private static final String BROKER_USER_ID = "brokerUserId";
    private static final String BROKER_SESSION_ID = "brokerSessionId";
    private final UserSessionDao dao;

    @Override
    public void insert(UserSession session) {
        insert(session, null);
    }

    @Override
    public void update(UserSession session) {
        update(session, null);
    }

    @Override
    public void insert(UserSession session, String correspondingSessionId) {
        if (correspondingSessionId != null) {
            insertOrUpdate(session, new UserSessionToAttributeMapping(session.getId(), CORRESPONDING_SESSION_ID, Arrays.asList(correspondingSessionId)));
            session.getNotes().put(CORRESPONDING_SESSION_ID, correspondingSessionId); // compatibility
        }

        insertOrUpdate(session);

        if (session.getUserId() != null) {
            insertOrUpdate(session, new UserSessionToAttributeMapping(session.getId(), USER_ID, Arrays.asList(session.getUserId())));
        }

        if (session.getBrokerUserId() != null) {
            insertOrUpdate(session, new UserSessionToAttributeMapping(session.getId(), BROKER_USER_ID, Arrays.asList(session.getBrokerUserId())));
        }

        if (session.getBrokerSessionId() != null) {
            insertOrUpdate(session, new UserSessionToAttributeMapping(session.getId(), BROKER_SESSION_ID, Arrays.asList(session.getBrokerSessionId())));
        }
    }

    @Override
    public void update(UserSession session, String correspondingSessionId) {
        if (correspondingSessionId != null) {
            insertOrUpdate(session, new UserSessionToAttributeMapping(session.getId(), CORRESPONDING_SESSION_ID, Arrays.asList(correspondingSessionId)));
            session.getNotes().put(CORRESPONDING_SESSION_ID, correspondingSessionId); // compatibility
        }

        insertOrUpdate(session);
    }

    @Override
    public void addClientSession(UserSession session, AuthenticatedClientSessionValue clientSession) {
        session.getClientSessions().put(clientSession.getClientId(), clientSession);

        UserSessionToAttributeMapping clientIdsAttribute = new UserSessionToAttributeMapping(session.getId(), CLIENT_IDS, new ArrayList<>());

        for (String clientId : session.getClientSessions().keySet()) {
            clientIdsAttribute.getAttributeValues().add(clientId);
        }

        if (!clientIdsAttribute.getAttributeValues().isEmpty()) {
            insertOrUpdate(session, clientIdsAttribute);
        }

        insertOrUpdate(session);
    }

    @Override
    public UserSession findUserSessionById(String id) {
        return dao.findById(id);
    }

    @Override
    public List findAll() {
        return dao.findAll().all();
    }

    @Override
    public List findUserSessionsByBrokerSession(String brokerSessionId) {
        return findUserSessionsByAttribute(BROKER_SESSION_ID, brokerSessionId);
    }

    @Override
    public List findUserSessionsByUserId(String userId) {
        return findUserSessionsByAttribute(USER_ID, userId);
    }

    @Override
    public List findUserSessionsByClientId(String clientId) {
        return findUserSessionsByAttribute(CLIENT_IDS, clientId);
    }

    @Override
    public List findUserSessionsByBrokerUserId(String brokerUserId) {
        return findUserSessionsByAttribute(BROKER_USER_ID, brokerUserId);
    }

    @Override
    public void deleteUserSession(UserSession session) {
        deleteUserSession(session.getId());
    }

    @Override
    public void deleteUserSession(String id) {
        dao.deleteUserSession(id);

        // Attributes
        for (UserSessionToAttributeMapping attribute : dao.findAllAttributes(id)) {
            for (String attributeValue : attribute.getAttributeValues()) {
                dao.deleteAttributeToUserSessionMapping(attribute.getAttributeName(), attributeValue, id);
            }
        }

        dao.deleteAllUserSessionToAttributeMappings(id);
    }

    @Override
    public void deleteCorrespondingUserSession(UserSession session) {
        if (!session.getNotes().containsKey(CORRESPONDING_SESSION_ID)) {
            return;
        }

        deleteUserSession(session.getNotes().get(CORRESPONDING_SESSION_ID));
    }

    // Attributes
    @Override
    public Set findUserSessionIdsByAttribute(String name, String value, int firstResult, int maxResult) {
        return StreamExtensions.paginated(dao.findByAttribute(name, value), firstResult, maxResult)
            .map(AttributeToUserSessionMapping::getUserSessionId)
            .collect(Collectors.toSet());
    }

    @Override
    public List findUserSessionsByAttribute(String name, String value) {
        List userIds = dao.findByAttribute(name, value).all().stream()
            .map(AttributeToUserSessionMapping::getUserSessionId)
            .collect(Collectors.toList());

        return dao.findByIds(userIds).all();
    }

    @Override
    public UserSession findUserSessionByAttribute(String name, String value) {
        List userSessions = findUserSessionsByAttribute(name, value);

        if (userSessions.size() > 1) {
            throw new IllegalStateException("Found more than one userSession with attributeName " + name + " and value " + value);
        }

        if (userSessions.isEmpty()) {
            return null;
        }

        return userSessions.get(0);
    }

    @Override
    public MultivaluedHashMap findAllUserSessionAttributes(String userSessionId) {
        List attributeMappings = dao.findAllAttributes(userSessionId).all();
        MultivaluedHashMap result = new MultivaluedHashMap<>();

        attributeMappings.forEach(mapping -> result.addAll(mapping.getAttributeName(), mapping.getAttributeValues()));

        return result;
    }

    @Override
    public UserSessionToAttributeMapping findUserSessionAttribute(String userSessionId, String attributeName) {
        return dao.findAttribute(userSessionId, attributeName);
    }

    private void insertOrUpdate(UserSession session) {
        if ((session.getOffline() != null && session.getOffline()) || PERSISTENT.equals(session.getPersistenceState())) {
            if (session.getExpiration() == null) {
                dao.insertOrUpdate(session);
            } else {
                int ttl = TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(TimeAdapter.fromMilliSecondsToSeconds(session.getExpiration() - Time.currentTimeMillis()));
                dao.insertOrUpdate(session, ttl);
            }
        }
    }

    private void insertOrUpdate(UserSession session, UserSessionToAttributeMapping mapping) {
        Integer ttl = session.getExpiration() == null ? null : TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(TimeAdapter.fromMilliSecondsToSeconds(session.getExpiration() - Time.currentTimeMillis()));
        UserSessionToAttributeMapping oldAttribute = dao.findAttribute(mapping.getUserSessionId(), mapping.getAttributeName());

        if(ttl == null) {
            dao.insertOrUpdate(mapping);
        } else {
            dao.insertOrUpdate(mapping, ttl);
        }

        if (oldAttribute != null) {
            // Alte AttributeToUserSessionMappings löschen, da die Values als Teil des PartitionKey nicht
            // geändert werden können
            oldAttribute
                .getAttributeValues()
                .forEach(value -> dao.deleteAttributeToUserSessionMapping(oldAttribute.getAttributeName(), value, oldAttribute.getUserSessionId()));
        }

        mapping
            .getAttributeValues()
            .forEach(
                value -> {
                    AttributeToUserSessionMapping attributeToUserSessionMapping =
                        new AttributeToUserSessionMapping(
                            mapping.getAttributeName(),
                            value,
                            mapping.getUserSessionId());

                    if(ttl == null) {
                        dao.insert(attributeToUserSessionMapping);
                    } else {
                        dao.insert(attributeToUserSessionMapping, ttl);
                    }
                });
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy