diff --git a/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyContextService.java b/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyContextService.java
new file mode 100644
index 0000000000..7491b7b870
--- /dev/null
+++ b/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyContextService.java
@@ -0,0 +1,193 @@
+/*
+ * This file is part of *** M y C o R e ***
+ * See https://www.mycore.de/ for details.
+ *
+ * MyCoRe is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * MyCoRe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MyCoRe. If not, see .
+ */
+
+package org.mycore.mcr.acl.accesskey.service;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+import org.mycore.access.MCRAccessCacheHelper;
+import org.mycore.access.MCRAccessManager;
+import org.mycore.datamodel.metadata.MCRMetadataManager;
+import org.mycore.datamodel.metadata.MCRObjectID;
+import org.mycore.mcr.acl.accesskey.dto.MCRAccessKeyDto;
+import org.mycore.mcr.acl.accesskey.exception.MCRAccessKeyException;
+import org.mycore.mcr.acl.accesskey.exception.MCRAccessKeyNotFoundException;
+
+/**
+ * Service that provides methods to active or deactivate access key for context.
+ *
+ * @param the context
+ */
+public abstract class MCRAccessKeyContextService {
+
+ private final MCRAccessKeyService accessKeyService;
+
+ /**
+ * Constructs new {@link MCRAccessKeyContextService} instance.
+ *
+ * @param accessKeyService the access key service
+ */
+ public MCRAccessKeyContextService(MCRAccessKeyService accessKeyService) {
+ this.accessKeyService = accessKeyService;
+ }
+
+ /**
+ * Activates a access key for reference by secret to current context.
+ *
+ * @param reference the object or resource reference for which the access key will be activated
+ * @param secret the secret to active access key
+ * @throws UnsupportedOperationException if the reference is not supported
+ * @throws MCRAccessKeyException if no access key has been activated
+ */
+ public void activateAccessKey(String reference, String secret) {
+ if (MCRObjectID.isValid(reference)) {
+ activateAccessKeyForObject(MCRObjectID.getInstance(reference), secret);
+ } else {
+ throw new UnsupportedOperationException("Reference: " + reference + " is not supported");
+ }
+ }
+
+ /**
+ * Retrieves the currently activated access key for the given reference.
+ *
+ * @param reference the reference for which the access key is retrieved
+ * @return the activated {@link MCRAccessKeyDto}, or {@code null} if no key is active
+ */
+ public MCRAccessKeyDto findActiveAccessKey(String reference) {
+ return Optional.ofNullable(getAccessKeyFromContext(getCurrentContext(), getAttributeName(reference)))
+ .map(v -> accessKeyService.findAccessKeyByReferenceAndSecret(reference, v)).orElse(null);
+ }
+
+ /**
+ * Deactivates the access key for the given reference in the current context.
+ *
+ * @param reference the reference for which the access key will be deactivated
+ */
+ public void deactivateAccessKey(String reference) {
+ removeAccessKeyFromContext(getCurrentContext(), getAttributeName(reference));
+ MCRAccessCacheHelper.clearPermissionCache(reference);
+ }
+
+ /**
+ * Returns the {@link MCRAccessKeyService} used to manage access keys.
+ *
+ * @return the access key service
+ */
+ protected MCRAccessKeyService getService() {
+ return accessKeyService;
+ }
+
+ private String getAttributeName(String reference) {
+ return getAccessKeyAttributePrefix() + reference;
+ }
+
+ private void addAccessKeyForObjectToContext(T context, MCRObjectID objectId, String secret) {
+ final String processedSecret = accessKeyService.processSecret(objectId.toString(), secret);
+ final MCRAccessKeyDto accessKeyDto
+ = accessKeyService.findAccessKeyByReferenceAndSecret(objectId.toString(), processedSecret);
+ if (accessKeyDto == null) {
+ throw new MCRAccessKeyNotFoundException("Access key is invalid.");
+ } else if (isAccessKeyAllowedInContext(accessKeyDto)) {
+ setAccessKeyAttribute(context, getAttributeName(objectId.toString()), processedSecret);
+ MCRAccessManager.invalidPermissionCacheByID(objectId.toString());
+ } else {
+ throw new MCRAccessKeyException("Access key is not allowed.");
+ }
+ }
+
+ private void activateAccessKeyForObject(MCRObjectID objectId, String secret) {
+ if (!MCRMetadataManager.exists(objectId)) {
+ throw new MCRAccessKeyException("No access key could be activated");
+ }
+ final T context = getCurrentContext();
+ if ("derivate".equals(objectId.getTypeId())) {
+ addAccessKeyForObjectToContext(context, objectId, secret);
+ } else {
+ boolean success = false;
+ try {
+ addAccessKeyForObjectToContext(context, objectId, secret);
+ MCRAccessCacheHelper.clearPermissionCache(objectId.toString());
+ success = true;
+ } catch (MCRAccessKeyException e) {
+ // ignored
+ }
+ final List derivateIds = MCRMetadataManager.getDerivateIds(objectId, 0, TimeUnit.SECONDS);
+ for (final MCRObjectID derivateId : derivateIds) {
+ try {
+ addAccessKeyForObjectToContext(context, derivateId, secret);
+ success = true;
+ } catch (MCRAccessKeyException e) {
+ // ignored
+ }
+ }
+ if (!success) {
+ throw new MCRAccessKeyException("No access key could be activated");
+ }
+ }
+ }
+
+ /**
+ * Returns the current context in which access keys are managed.
+ *
+ * @return the current context
+ */
+ abstract T getCurrentContext();
+
+ /**
+ * Adds an access key attribute to the given context.
+ *
+ * @param context the context in which the access key attribute is added
+ * @param attributeName the name of the attribute to be added
+ * @param secret the secret of the access key
+ */
+ abstract void setAccessKeyAttribute(T context, String attributeName, String secret);
+
+ /**
+ * Checks if adding the access key to the context is allowed based on the provided access key DTO.
+ *
+ * @param accessKeyDto the access key data transfer object
+ * @return {@code true} if adding the access key is allowed, {@code false} otherwise
+ */
+ abstract boolean isAccessKeyAllowedInContext(MCRAccessKeyDto accessKeyDto);
+
+ /**
+ * Deletes the access key attribute from the given context.
+ *
+ * @param context the context from which the access key attribute is removed
+ * @param attributeName the name of the attribute to be removed
+ */
+ abstract void removeAccessKeyFromContext(T context, String attributeName);
+
+ /**
+ * Retrieves the secret of the access key attribute from the given context.
+ *
+ * @param context the context from which the attribute secret is retrieved
+ * @param attributeName the name of the attribute
+ * @return the secret of the access key attribute, or {@code null} if no attribute is found
+ */
+ abstract String getAccessKeyFromContext(T context, String attributeName);
+
+ /**
+ * Returns the prefix to be used for access key attribute names.
+ *
+ * @return the prefix for attribute names
+ */
+ abstract String getAccessKeyAttributePrefix();
+}
diff --git a/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyServiceFactory.java b/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyServiceFactory.java
index 7c035f3632..f0367bd96a 100644
--- a/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyServiceFactory.java
+++ b/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyServiceFactory.java
@@ -38,8 +38,16 @@ public final class MCRAccessKeyServiceFactory {
private static volatile MCRAccessKeyService service;
+ private static volatile MCRAccessKeyUserService userService;
+
+ private static volatile MCRAccessKeySessionService sessionService;
+
private static final Lock SERVICE_LOCK = new ReentrantLock();
+ private static final Lock USER_SERVICE_LOCK = new ReentrantLock();
+
+ private static final Lock SESSION_SERVICE_LOCK = new ReentrantLock();
+
private MCRAccessKeyServiceFactory() {
}
@@ -64,6 +72,52 @@ public static MCRAccessKeyService getAccessKeyService() {
return service;
}
+ /**
+ * Returns single access key user service instance.
+ *
+ * @return the instance
+ */
+ public static MCRAccessKeyUserService getAccessKeyUserService() {
+ if (userService == null) {
+ try {
+ USER_SERVICE_LOCK.lock();
+ if (userService == null) {
+ userService = createUserService(getAccessKeyService());
+ }
+ } finally {
+ USER_SERVICE_LOCK.unlock();
+ }
+ }
+ return userService;
+ }
+
+ /**
+ * Returns single access key session service instance.
+ *
+ * @return the instance
+ */
+ public static MCRAccessKeySessionService getAccessKeySessionService() {
+ if (sessionService == null) {
+ try {
+ SESSION_SERVICE_LOCK.lock();
+ if (sessionService == null) {
+ sessionService = createSessionService(getAccessKeyService());
+ }
+ } finally {
+ SESSION_SERVICE_LOCK.unlock();
+ }
+ }
+ return sessionService;
+ }
+
+ private static MCRAccessKeyUserService createUserService(MCRAccessKeyService service) {
+ return new MCRAccessKeyUserService(service);
+ }
+
+ private static MCRAccessKeySessionService createSessionService(MCRAccessKeyService service) {
+ return new MCRAccessKeySessionService(service);
+ }
+
private static MCRAccessKeyService createAndConfigureService(MCRAccessKeyRepository accessKeyRepository,
MCRAccessKeyValidator validator, MCRAccessKeySecretProcessor secretProcessor) {
return new MCRAccessKeyServiceImpl(accessKeyRepository, validator, secretProcessor);
diff --git a/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeySessionService.java b/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeySessionService.java
new file mode 100644
index 0000000000..69ad08c643
--- /dev/null
+++ b/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeySessionService.java
@@ -0,0 +1,75 @@
+/*
+ * This file is part of *** M y C o R e ***
+ * See https://www.mycore.de/ for details.
+ *
+ * MyCoRe is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * MyCoRe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MyCoRe. If not, see .
+ */
+
+package org.mycore.mcr.acl.accesskey.service;
+
+import org.mycore.common.MCRSession;
+import org.mycore.common.MCRSessionMgr;
+import org.mycore.mcr.acl.accesskey.config.MCRAccessKeyConfig;
+import org.mycore.mcr.acl.accesskey.dto.MCRAccessKeyDto;
+
+/**
+ * Implements {@link MCRAccessKeyContextService} for {@link MCRSession} context.
+ */
+public class MCRAccessKeySessionService extends MCRAccessKeyContextService {
+
+ /**
+ * Prefix for session attribute name for secret.
+ */
+ public static final String ACCESS_KEY_SESSION_ATTRIBUTE_PREFIX = "acckey_";
+
+ /**
+ * Constructs new {@link MCRAccessKeySessionService} with given {@link MCRAccessKeyService}.
+ *
+ * @param accessKeyService the access key service
+ */
+ public MCRAccessKeySessionService(MCRAccessKeyService accessKeyService) {
+ super(accessKeyService);
+ }
+
+ @Override
+ MCRSession getCurrentContext() {
+ return MCRSessionMgr.getCurrentSession();
+ }
+
+ @Override
+ protected void setAccessKeyAttribute(MCRSession context, String attributeName, String secret) {
+ context.put(attributeName, secret);
+ }
+
+ @Override
+ protected boolean isAccessKeyAllowedInContext(MCRAccessKeyDto accessKeyDto) {
+ return MCRAccessKeyConfig.getAllowedSessionPermissionTypes().contains(accessKeyDto.getPermission());
+ }
+
+ @Override
+ protected void removeAccessKeyFromContext(MCRSession context, String attributeName) {
+ context.deleteObject(attributeName);
+ }
+
+ @Override
+ protected String getAccessKeyFromContext(MCRSession context, String attributeName) {
+ return (String) context.get(attributeName);
+ }
+
+ @Override
+ protected String getAccessKeyAttributePrefix() {
+ return ACCESS_KEY_SESSION_ATTRIBUTE_PREFIX;
+ }
+
+}
diff --git a/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyUserService.java b/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyUserService.java
new file mode 100644
index 0000000000..548671e4be
--- /dev/null
+++ b/mycore-acl/src/main/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyUserService.java
@@ -0,0 +1,130 @@
+/*
+ * This file is part of *** M y C o R e ***
+ * See https://www.mycore.de/ for details.
+ *
+ * MyCoRe is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * MyCoRe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MyCoRe. If not, see .
+ */
+
+package org.mycore.mcr.acl.accesskey.service;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.mycore.mcr.acl.accesskey.dto.MCRAccessKeyDto;
+import org.mycore.user2.MCRUser;
+import org.mycore.user2.MCRUserAttribute;
+import org.mycore.user2.MCRUserManager;
+
+/**
+ * Implements {@link MCRAccessKeyContextService} for {@link MCRUser} context.
+ */
+public class MCRAccessKeyUserService extends MCRAccessKeyContextService {
+
+ /**
+ * Prefix for user attribute name for secret.
+ */
+ public static final String ACCESS_KEY_USER_ATTRIBUTE_PREFIX = "acckey_";
+
+ /**
+ * Creates new {@link MCRAccessKeyUserService} with {@link MCRAccessKeyService}.
+ *
+ * @param accessKeyService the access key service
+ */
+ public MCRAccessKeyUserService(MCRAccessKeyService accessKeyService) {
+ super(accessKeyService);
+ }
+
+ @Override
+ protected MCRUser getCurrentContext() {
+ return MCRUserManager.getCurrentUser();
+ }
+
+ @Override
+ protected void setAccessKeyAttribute(MCRUser context, String attributeName, String secret) {
+ context.setUserAttribute(attributeName, secret);
+ MCRUserManager.updateUser(context);
+ }
+
+ @Override
+ protected boolean isAccessKeyAllowedInContext(MCRAccessKeyDto accessKeyDto) {
+ return true;
+ }
+
+ @Override
+ protected void removeAccessKeyFromContext(MCRUser context, String attributeName) {
+ context.getAttributes().removeIf(ua -> ua.getName().equals(attributeName));
+ MCRUserManager.updateUser(context);
+ }
+
+ @Override
+ protected String getAccessKeyFromContext(MCRUser context, String attributeName) {
+ return context.getUserAttribute(attributeName);
+ }
+
+ @Override
+ String getAccessKeyAttributePrefix() {
+ return ACCESS_KEY_USER_ATTRIBUTE_PREFIX;
+ }
+
+ /**
+ * Cleans up user attributes related to access keys by checking their validity.
+ *
+ * This method iterates over all users who have access key attributes and ensures that only valid access key
+ * attributes are retained. It removes access key attributes if they are invalid or have been deleted.
+ */
+ public void cleanUpUserAttributes() {
+ final Set validAttributes = new HashSet<>();
+ final Set deadAttributes = new HashSet<>();
+ final int limit = 1024;
+ int offset = 0;
+ List users;
+ do {
+ users = listUsersWithAccessKey(offset, limit);
+ for (MCRUser user : users) {
+ cleanUpAttributesForUser(user, validAttributes, deadAttributes);
+ }
+ offset += limit;
+ } while (users.size() == limit);
+ }
+
+ private static List listUsersWithAccessKey(int offset, int limit) {
+ return MCRUserManager.listUsers(null, null, null, null, ACCESS_KEY_USER_ATTRIBUTE_PREFIX + "*", null, offset,
+ limit);
+ }
+
+ private String extractReference(MCRUserAttribute attribute) {
+ return attribute.getName().substring(attribute.getName().indexOf('_') + 1);
+ }
+
+ private void cleanUpAttributesForUser(MCRUser user, Set validAttributes,
+ Set deadAttributes) {
+ final List attributes = user.getAttributes().stream()
+ .filter(attr -> attr.getName().startsWith(ACCESS_KEY_USER_ATTRIBUTE_PREFIX))
+ .filter(attr -> !validAttributes.contains(attr)).collect(Collectors.toList());
+ for (MCRUserAttribute attribute : attributes) {
+ final String reference = extractReference(attribute);
+ if (deadAttributes.contains(attribute)) {
+ removeAccessKeyFromContext(user, ACCESS_KEY_USER_ATTRIBUTE_PREFIX + reference);
+ } else if (getService().findAccessKeyByReferenceAndSecret(reference, attribute.getValue()) != null) {
+ validAttributes.add(attribute);
+ } else {
+ removeAccessKeyFromContext(user, ACCESS_KEY_USER_ATTRIBUTE_PREFIX + reference);
+ deadAttributes.add(attribute);
+ }
+ }
+ }
+
+}
diff --git a/mycore-acl/src/test/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeySessionServiceImplTest.java b/mycore-acl/src/test/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeySessionServiceImplTest.java
new file mode 100644
index 0000000000..feee6a4247
--- /dev/null
+++ b/mycore-acl/src/test/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeySessionServiceImplTest.java
@@ -0,0 +1,198 @@
+/*
+ * This file is part of *** M y C o R e ***
+ * See https://www.mycore.de/ for details.
+ *
+ * MyCoRe is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * MyCoRe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MyCoRe. If not, see .
+ */
+
+package org.mycore.mcr.acl.accesskey.service;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mycore.access.MCRAccessException;
+import org.mycore.access.MCRAccessManager;
+import org.mycore.common.MCRPersistenceException;
+import org.mycore.common.MCRSessionMgr;
+import org.mycore.common.config.MCRConfiguration2;
+import org.mycore.datamodel.metadata.MCRDerivate;
+import org.mycore.datamodel.metadata.MCRMetadataManager;
+import org.mycore.datamodel.metadata.MCRObject;
+import org.mycore.datamodel.metadata.MCRObjectID;
+import org.mycore.mcr.acl.accesskey.MCRAccessKeyTestCase;
+import org.mycore.mcr.acl.accesskey.config.MCRAccessKeyConfig;
+import org.mycore.mcr.acl.accesskey.dto.MCRAccessKeyDto;
+import org.mycore.mcr.acl.accesskey.exception.MCRAccessKeyException;
+
+public class MCRAccessKeySessionServiceImplTest extends MCRAccessKeyTestCase {
+
+ private static final String READ_KEY = "blah";
+
+ private static final String WRITE_KEY = "blub";
+
+ private static final String DELETE_KEY = "delete";
+
+ private static final String UNKNOWN_KEY = "unknown";
+
+ private MCRObject object;
+
+ private MCRDerivate derivate;
+
+ private MCRObjectID unknownObjectId;
+
+ private MCRAccessKeyService accessKeyServiceMock;
+
+ private MCRAccessKeySessionService sessionService;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ object = createObject();
+ MCRMetadataManager.create(object);
+ derivate = createDerivate(object.getId());
+ MCRMetadataManager.create(derivate);
+ unknownObjectId = MCRObjectID.getInstance("mcr_object_00000002");
+ accessKeyServiceMock = Mockito.mock(MCRAccessKeyService.class);
+ Mockito.when(accessKeyServiceMock.processSecret(object.getId().toString(), READ_KEY)).thenReturn(READ_KEY);
+ Mockito.when(accessKeyServiceMock.processSecret(derivate.getId().toString(), WRITE_KEY)).thenReturn(WRITE_KEY);
+ Mockito.when(accessKeyServiceMock.processSecret(object.getId().toString(), UNKNOWN_KEY)).thenReturn(UNKNOWN_KEY);
+ Mockito.when(accessKeyServiceMock.processSecret(object.getId().toString(), DELETE_KEY)).thenReturn(DELETE_KEY);
+ final MCRAccessKeyDto readAccessKeyDto = new MCRAccessKeyDto();
+ readAccessKeyDto.setReference(object.getId().toString());
+ readAccessKeyDto.setSecret(READ_KEY);
+ readAccessKeyDto.setPermission(MCRAccessManager.PERMISSION_READ);
+ final MCRAccessKeyDto writeAccessKeyDto = new MCRAccessKeyDto();
+ writeAccessKeyDto.setReference(object.getId().toString());
+ writeAccessKeyDto.setSecret(WRITE_KEY);
+ writeAccessKeyDto.setPermission(MCRAccessManager.PERMISSION_WRITE);
+ final MCRAccessKeyDto deleteAccessKeyDto = new MCRAccessKeyDto();
+ deleteAccessKeyDto.setReference(object.getId().toString());
+ deleteAccessKeyDto.setSecret(DELETE_KEY);
+ deleteAccessKeyDto.setPermission(MCRAccessManager.PERMISSION_DELETE);
+ Mockito.when(accessKeyServiceMock.findAccessKeyByReferenceAndSecret(object.getId().toString(), READ_KEY))
+ .thenReturn(readAccessKeyDto);
+ Mockito.when(accessKeyServiceMock.findAccessKeyByReferenceAndSecret(derivate.getId().toString(), WRITE_KEY))
+ .thenReturn(writeAccessKeyDto);
+ Mockito.when(accessKeyServiceMock.findAccessKeyByReferenceAndSecret(object.getId().toString(), UNKNOWN_KEY))
+ .thenReturn(null);
+ sessionService = new MCRAccessKeySessionService(accessKeyServiceMock);
+ }
+
+ @Test
+ public void testSetup() throws MCRPersistenceException, MCRAccessException {
+ assertTrue(MCRMetadataManager.exists(object.getId()));
+ assertTrue(MCRMetadataManager.exists(derivate.getId()));
+ }
+
+ @Test
+ public void testActivateAccessKeyForReferenceByRawValue_object() {
+ sessionService.activateAccessKey(object.getId().toString(), READ_KEY);
+ assertEquals(READ_KEY, MCRSessionMgr.getCurrentSession()
+ .get(MCRAccessKeySessionService.ACCESS_KEY_SESSION_ATTRIBUTE_PREFIX + object.getId().toString()));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(1)).findAccessKeyByReferenceAndSecret(
+ object.getId().toString(), READ_KEY);
+ }
+
+ @Test
+ public void testActivateObjectAccessKeyForReferenceByRawValue_derivate_allowed() {
+ MCRConfiguration2.set(MCRAccessKeyConfig.ALLOWED_SESSION_PERMISSION_TYPES_PROP, "read,writedb");
+ sessionService.activateAccessKey(derivate.getId().toString(), WRITE_KEY);
+ assertEquals(WRITE_KEY, MCRSessionMgr.getCurrentSession()
+ .get(MCRAccessKeySessionService.ACCESS_KEY_SESSION_ATTRIBUTE_PREFIX + derivate.getId().toString()));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(1))
+ .findAccessKeyByReferenceAndSecret(derivate.getId().toString(), WRITE_KEY);
+ }
+
+ @Test
+ public void testActivateObjectAccessKeyForReferenceByRawValue_derivate_notAllowed() {
+ MCRConfiguration2.set(MCRAccessKeyConfig.ALLOWED_SESSION_PERMISSION_TYPES_PROP, "read");
+ assertThrows(MCRAccessKeyException.class,
+ () -> sessionService.activateAccessKey(derivate.getId().toString(), WRITE_KEY));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(1))
+ .findAccessKeyByReferenceAndSecret(derivate.getId().toString(), WRITE_KEY);
+ }
+
+ @Test
+ public void testActivateObjectAccessKeyForReferenceByRawValue_unknownObject() {
+ assertThrows(MCRAccessKeyException.class,
+ () -> sessionService.activateAccessKey(unknownObjectId.toString(), WRITE_KEY));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(0)).findAccessKeyByReferenceAndSecret(Mockito.anyString(),
+ Mockito.anyString());
+ }
+
+ @Test
+ public void testActivateObjectAccessKeyForReferenceByRawValue_unknownAccessKey() {
+ assertThrows(MCRAccessKeyException.class,
+ () -> sessionService.activateAccessKey(object.getId().toString(), UNKNOWN_KEY));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(1)).findAccessKeyByReferenceAndSecret(
+ object.getId().toString(), UNKNOWN_KEY);
+ }
+
+ @Test
+ public void testActivateObjectAccessKeyForReferenceByRawValue_permissionNotAllowed() {
+ assertThrows(MCRAccessKeyException.class,
+ () -> sessionService.activateAccessKey(object.getId().toString(), DELETE_KEY));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(1)).findAccessKeyByReferenceAndSecret(
+ object.getId().toString(), DELETE_KEY);
+ }
+
+ @Test
+ public void testActivateObjectAccessKeyForReferenceByRawValue_override() {
+ MCRSessionMgr.getCurrentSession()
+ .put(MCRAccessKeySessionService.ACCESS_KEY_SESSION_ATTRIBUTE_PREFIX + object.getId().toString(), WRITE_KEY);
+ sessionService.activateAccessKey(object.getId().toString(), READ_KEY);
+ assertEquals(READ_KEY, MCRSessionMgr.getCurrentSession()
+ .get(MCRAccessKeySessionService.ACCESS_KEY_SESSION_ATTRIBUTE_PREFIX + object.getId().toString()));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(1))
+ .findAccessKeyByReferenceAndSecret(object.getId().toString(), READ_KEY);
+ }
+
+ @Test
+ public void testGetActivatedAccessKeyForReference() {
+ MCRSessionMgr.getCurrentSession()
+ .put(MCRAccessKeySessionService.ACCESS_KEY_SESSION_ATTRIBUTE_PREFIX + object.getId().toString(), READ_KEY);
+ final MCRAccessKeyDto accessKey = sessionService.findActiveAccessKey(object.getId().toString());
+ assertNotNull(accessKey);
+ assertEquals(READ_KEY, sessionService.findActiveAccessKey(object.getId().toString()).getSecret());
+ }
+
+ @Test
+ public void testGetActivatedAccessKeyForReference_notExists() {
+ assertNull(sessionService.findActiveAccessKey(object.getId().toString()));
+ }
+
+ @Test
+ public void testRemoveAccessKeySecretFromCurrentSession() {
+ MCRSessionMgr.getCurrentSession()
+ .put(MCRAccessKeySessionService.ACCESS_KEY_SESSION_ATTRIBUTE_PREFIX + object.getId().toString(), READ_KEY);
+ sessionService.deactivateAccessKey(object.getId().toString());
+ assertNull(MCRSessionMgr.getCurrentSession()
+ .get(MCRAccessKeySessionService.ACCESS_KEY_SESSION_ATTRIBUTE_PREFIX + object.getId().toString()));
+ }
+
+ @After
+ public void teardown() throws Exception {
+ MCRMetadataManager.delete(derivate);
+ MCRMetadataManager.delete(object);
+ super.tearDown();
+ }
+}
diff --git a/mycore-acl/src/test/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyUserServiceImplTest.java b/mycore-acl/src/test/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyUserServiceImplTest.java
new file mode 100644
index 0000000000..0698a0ad79
--- /dev/null
+++ b/mycore-acl/src/test/java/org/mycore/mcr/acl/accesskey/service/MCRAccessKeyUserServiceImplTest.java
@@ -0,0 +1,207 @@
+/*
+ * This file is part of *** M y C o R e ***
+ * See https://www.mycore.de/ for details.
+ *
+ * MyCoRe is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * MyCoRe is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MyCoRe. If not, see .
+ */
+
+package org.mycore.mcr.acl.accesskey.service;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mycore.access.MCRAccessManager;
+import org.mycore.common.MCRSessionMgr;
+import org.mycore.common.MCRSystemUserInformation;
+import org.mycore.datamodel.metadata.MCRDerivate;
+import org.mycore.datamodel.metadata.MCRMetadataManager;
+import org.mycore.datamodel.metadata.MCRObject;
+import org.mycore.datamodel.metadata.MCRObjectID;
+import org.mycore.mcr.acl.accesskey.MCRAccessKeyTestCase;
+import org.mycore.mcr.acl.accesskey.dto.MCRAccessKeyDto;
+import org.mycore.mcr.acl.accesskey.exception.MCRAccessKeyException;
+import org.mycore.user2.MCRUser;
+import org.mycore.user2.MCRUserManager;
+
+public class MCRAccessKeyUserServiceImplTest extends MCRAccessKeyTestCase {
+
+ private static final String READ_KEY = "blah";
+
+ private static final String WRITE_KEY = "blub";
+
+ private static final String DELETE_KEY = "delete";
+
+ private static final String UNKNOWN_KEY = "unknown";
+
+ private MCRObject object = null;
+
+ private MCRDerivate derivate = null;
+
+ private MCRObjectID unknownObjectId = null;
+
+ private MCRAccessKeyService accessKeyServiceMock;
+
+ private MCRAccessKeyUserService userService;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ object = createObject();
+ MCRMetadataManager.create(object);
+ derivate = createDerivate(object.getId());
+ MCRMetadataManager.create(derivate);
+ unknownObjectId = MCRObjectID.getInstance("mcr_object_00000002");
+ accessKeyServiceMock = Mockito.mock(MCRAccessKeyService.class);
+ Mockito.when(accessKeyServiceMock.processSecret(object.getId().toString(), READ_KEY)).thenReturn(READ_KEY);
+ Mockito.when(accessKeyServiceMock.processSecret(derivate.getId().toString(), WRITE_KEY)).thenReturn(WRITE_KEY);
+ Mockito.when(accessKeyServiceMock.processSecret(object.getId().toString(), UNKNOWN_KEY)).thenReturn(UNKNOWN_KEY);
+ Mockito.when(accessKeyServiceMock.processSecret(object.getId().toString(), DELETE_KEY)).thenReturn(DELETE_KEY);
+ final MCRAccessKeyDto readAccessKeyDto = new MCRAccessKeyDto();
+ readAccessKeyDto.setReference(object.getId().toString());
+ readAccessKeyDto.setSecret(READ_KEY);
+ readAccessKeyDto.setPermission(MCRAccessManager.PERMISSION_READ);
+ final MCRAccessKeyDto writeAccessKeyDto = new MCRAccessKeyDto();
+ writeAccessKeyDto.setReference(object.getId().toString());
+ writeAccessKeyDto.setSecret(WRITE_KEY);
+ writeAccessKeyDto.setPermission(MCRAccessManager.PERMISSION_WRITE);
+ final MCRAccessKeyDto deleteAccessKeyDto = new MCRAccessKeyDto();
+ deleteAccessKeyDto.setReference(object.getId().toString());
+ deleteAccessKeyDto.setSecret(DELETE_KEY);
+ deleteAccessKeyDto.setPermission(MCRAccessManager.PERMISSION_DELETE);
+ Mockito.when(accessKeyServiceMock.findAccessKeyByReferenceAndSecret(object.getId().toString(), READ_KEY))
+ .thenReturn(readAccessKeyDto);
+ Mockito.when(accessKeyServiceMock.findAccessKeyByReferenceAndSecret(derivate.getId().toString(), WRITE_KEY))
+ .thenReturn(writeAccessKeyDto);
+ Mockito.when(accessKeyServiceMock.findAccessKeyByReferenceAndSecret(object.getId().toString(), UNKNOWN_KEY))
+ .thenReturn(null);
+ userService = new MCRAccessKeyUserService(accessKeyServiceMock);
+ final MCRUser user = new MCRUser("junit");
+ MCRUserManager.createUser(user);
+ MCRSessionMgr.getCurrentSession().setUserInformation(user);
+ }
+
+ @Test
+ public void testSetup() {
+ assertTrue(MCRMetadataManager.exists(object.getId()));
+ assertTrue(MCRMetadataManager.exists(derivate.getId()));
+ }
+
+ @Test
+ public void testActivateAccessKeyForReferenceByRawValue_object() {
+ userService.activateAccessKey(object.getId().toString(), READ_KEY);
+ assertEquals(READ_KEY, MCRUserManager.getCurrentUser()
+ .getUserAttribute(MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + object.getId().toString()));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(1)).findAccessKeyByReferenceAndSecret(
+ object.getId().toString(), READ_KEY);
+ }
+
+ @Test
+ public void testActivateAccessKeyForReferenceByRawValue_derivate() {
+ userService.activateAccessKey(derivate.getId().toString(), WRITE_KEY);
+ assertEquals(WRITE_KEY, MCRUserManager.getCurrentUser()
+ .getUserAttribute(MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + derivate.getId().toString()));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(1)).findAccessKeyByReferenceAndSecret(
+ derivate.getId().toString(), WRITE_KEY);
+ }
+
+ @Test
+ public void testActivateAccessKeyForReferenceByRawValue_unknownObject() {
+ assertThrows(MCRAccessKeyException.class,
+ () -> userService.activateAccessKey(unknownObjectId.toString(), WRITE_KEY));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(0)).findAccessKeyByReferenceAndSecret(Mockito.anyString(),
+ Mockito.anyString());
+ }
+
+ @Test
+ public void testActivateAccessKeyForReferenceByRawValue_unknownAccessKey() {
+ assertThrows(MCRAccessKeyException.class,
+ () -> userService.activateAccessKey(object.getId().toString(), UNKNOWN_KEY));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(1)).findAccessKeyByReferenceAndSecret(
+ object.getId().toString(), UNKNOWN_KEY);
+ }
+
+ @Test
+ public void testActivateAccessKeyForReferenceByRawValue_override() {
+ MCRUserManager.getCurrentUser().setUserAttribute(
+ MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + object.getId().toString(), WRITE_KEY);
+ userService.activateAccessKey(object.getId().toString(), READ_KEY);
+ assertEquals(READ_KEY, MCRUserManager.getCurrentUser()
+ .getUserAttribute(MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + object.getId().toString()));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(1)).findAccessKeyByReferenceAndSecret(
+ object.getId().toString(), READ_KEY);
+ }
+
+ @Test
+ public void testGetActivatedAccessKeyForReference() {
+ MCRUserManager.getCurrentUser().setUserAttribute(
+ MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + object.getId().toString(), READ_KEY);
+ final MCRAccessKeyDto accessKey = userService.findActiveAccessKey(object.getId().toString());
+ assertNotNull(accessKey);
+ assertEquals(READ_KEY, userService.findActiveAccessKey(object.getId().toString()).getSecret());
+ }
+
+ @Test
+ public void testGetActivatedAccessKeyForReference_notExists() {
+ assertNull(userService.findActiveAccessKey(object.getId().toString()));
+ }
+
+ @Test
+ public void testRemoveAccessKeySecretFromCurrentSession() {
+ MCRUserManager.getCurrentUser().setUserAttribute(
+ MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + object.getId().toString(), READ_KEY);
+ userService.deactivateAccessKey(object.getId().toString());
+ assertNull(MCRUserManager.getCurrentUser()
+ .getUserAttribute(MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + object.getId().toString()));
+ }
+
+ @Test
+ public void testCleanUpUserAttributes() {
+ MCRUserManager.getCurrentUser().setUserAttribute(
+ MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + object.getId().toString(), UNKNOWN_KEY);
+ final MCRUser user = new MCRUser("junit1");
+ MCRUserManager.createUser(user);
+ MCRSessionMgr.getCurrentSession().setUserInformation(MCRSystemUserInformation.getGuestInstance());
+ MCRSessionMgr.getCurrentSession().setUserInformation(user);
+ MCRUserManager.getCurrentUser().setUserAttribute(
+ MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + object.getId().toString(), UNKNOWN_KEY);
+ MCRUserManager.getCurrentUser().setUserAttribute(
+ MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + derivate.getId().toString(), WRITE_KEY);
+ userService.cleanUpUserAttributes();
+ assertNull(MCRUserManager.getCurrentUser()
+ .getUserAttribute(MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + object.getId().toString()));
+ assertNotNull(MCRUserManager.getCurrentUser()
+ .getUserAttribute(MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + derivate.getId().toString()));
+ MCRSessionMgr.getCurrentSession().setUserInformation(MCRSystemUserInformation.getGuestInstance());
+ MCRSessionMgr.getCurrentSession().setUserInformation(MCRUserManager.getUser("junit"));
+ assertNull(MCRUserManager.getCurrentUser()
+ .getUserAttribute(MCRAccessKeyUserService.ACCESS_KEY_USER_ATTRIBUTE_PREFIX + object.getId().toString()));
+ Mockito.verify(accessKeyServiceMock, Mockito.times(2)).findAccessKeyByReferenceAndSecret(Mockito.anyString(),
+ Mockito.anyString());
+ }
+
+ @After
+ public void teardown() throws Exception {
+ MCRMetadataManager.delete(derivate);
+ MCRMetadataManager.delete(object);
+ super.tearDown();
+ }
+}