Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIR-1427 Use new access key api #1110

Open
wants to merge 2 commits into
base: 2024.06.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.mycore.mir.authorization;

import java.util.Date;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mycore.access.MCRAccessManager;
import org.mycore.access.strategies.MCRAccessCheckStrategy;
import org.mycore.datamodel.metadata.MCRObjectID;
import org.mycore.mcr.acl.accesskey.config.MCRAccessKeyConfig;
import org.mycore.mcr.acl.accesskey.dto.MCRAccessKeyDto;
import org.mycore.mcr.acl.accesskey.service.MCRAccessKeyServiceFactory;

/**
* Strategy class for checking access permissions on objects based on access keys.
* This class implements the {@link MCRAccessCheckStrategy} interface and provides methods
* to check permissions for both string-based object IDs and {@link MCRObjectID} instances.
*/
public class MIRAccessKeyStrategy implements MCRAccessCheckStrategy {

private static final Logger LOGGER = LogManager.getLogger();

@Override
public boolean checkPermission(String id, String permission) {
if (!MCRObjectID.isValid(id)) {
return false;
}
return checkObjectPermission(MCRObjectID.getInstance(id), permission);
}

/**
* Checks whether the specified permission is granted for the given {@link MCRObjectID}.
*
* @param objectId the {@link MCRObjectID} instance representing the object
* @param permission the requested permission (e.g., "read", "write")
* @return {@code true} if the permission is granted, {@code false} otherwise
*/
public boolean checkObjectPermission(MCRObjectID objectId, String permission) {
if (!MCRAccessKeyConfig.getAllowedObjectTypes().contains(objectId.getTypeId())) {
return false;
}
final String sanitizedPermission = sanitizePermission(permission);
if (!(MCRAccessManager.PERMISSION_WRITE.equals(sanitizedPermission)
|| MCRAccessManager.PERMISSION_READ.equals(sanitizedPermission))) {
return false;
}
if (MCRAccessKeyConfig.getAllowedSessionPermissionTypes().contains(sanitizedPermission)) {
if (checkSessionHasValidAccessKey(objectId.toString(), permission)) {
return true;
}
}
return checkUserHasValidAccessKey(objectId.toString(), permission);
}

private static String sanitizePermission(String permission) {
if (MCRAccessManager.PERMISSION_VIEW.equals(permission)
|| MCRAccessManager.PERMISSION_PREVIEW.equals(permission)) {
LOGGER.debug("Mapped {} to read.", permission);
return MCRAccessManager.PERMISSION_READ;
}
return permission;
}

private boolean checkSessionHasValidAccessKey(String objectId, String permission) {
final MCRAccessKeyDto accessKey
= MCRAccessKeyServiceFactory.getAccessKeySessionService().findActiveAccessKey(objectId);
if (accessKey != null) {
LOGGER.debug("Found match in access key strategy for {} on {} in session.", permission,
objectId);
return checkAccessKey(accessKey, permission);
}
return false;
}

private boolean checkUserHasValidAccessKey(String objectId, String permission) {
final MCRAccessKeyDto accessKey
= MCRAccessKeyServiceFactory.getAccessKeyUserService().findActiveAccessKey(objectId);
if (accessKey != null) {
LOGGER.debug("Found match in access key strategy for {} on {} in user attributes.", permission,
objectId);
return checkAccessKey(accessKey, permission);
}
return false;
}

private boolean checkAccessKey(MCRAccessKeyDto accessKey, String permission) {
if (MCRAccessManager.PERMISSION_READ.equals(permission)
|| MCRAccessManager.PERMISSION_WRITE.equals(permission)) {
if (Boolean.FALSE.equals(accessKey.getActive())) {
return false;
}
final Date expiration = accessKey.getExpiration();
if (expiration != null && new Date().after(expiration)) {
return false;
}
if ((permission.equals(MCRAccessManager.PERMISSION_READ)
&& accessKey.getPermission().equals(MCRAccessManager.PERMISSION_READ))
|| accessKey.getPermission().equals(MCRAccessManager.PERMISSION_WRITE)) {
LOGGER.debug("Access granted.");
return true;
}
}
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@
import org.mycore.datamodel.classifications2.MCRCategoryID;
import org.mycore.datamodel.metadata.MCRMetadataManager;
import org.mycore.datamodel.metadata.MCRObjectID;
import org.mycore.mcr.acl.accesskey.MCRAccessKeyManager;
import org.mycore.mcr.acl.accesskey.MCRAccessKeyUtils;
import org.mycore.mcr.acl.accesskey.model.MCRAccessKey;
import org.mycore.mcr.acl.accesskey.strategy.MCRAccessKeyStrategyHelper;
import org.mycore.mods.MCRMODSEmbargoUtils;
import org.mycore.pi.MCRPIManager;
import org.mycore.pi.MCRPIRegistrationInfo;
Expand Down Expand Up @@ -81,6 +77,8 @@ public class MIRStrategy implements MCRAccessCheckStrategy {

private static final MCRCreatorRuleStrategy CREATOR_STRATEGY = new MCRCreatorRuleStrategy();

private static final MIRAccessKeyStrategy ACCESS_KEY_OBJECT_STRATEGY = new MIRAccessKeyStrategy();

private static final long CACHE_TIME = 1000 * 60 * 60;

private final List<String> accessClasses;
Expand All @@ -98,43 +96,6 @@ public MIRStrategy() {
accessImpl = MCRAccessManager.getAccessImpl();
}

private boolean hasValidAccessKey(final MCRObjectID objectId, final String permission) {
boolean isWritePermission = MCRAccessManager.PERMISSION_WRITE.equals(permission);
boolean isReadPermission = MCRAccessManager.PERMISSION_READ.equals(permission);
if (isWritePermission || isReadPermission) {
if (MCRAccessKeyUtils.isAccessKeyForSessionAllowed(permission)) {
final String sessionSecret = MCRAccessKeyUtils.getAccessKeySecretFromCurrentSession(objectId);
if (sessionSecret != null) {
final MCRAccessKey accessKey = MCRAccessKeyManager.getAccessKeyWithSecret(objectId, sessionSecret);
if (accessKey != null) {
LOGGER.debug("Found match in access key strategy for {} on {} in session.", permission,
objectId);
if (MCRAccessKeyStrategyHelper.verifyAccessKey(permission, accessKey)) {
return true;
}
}
if (accessKey == null || permission.equals(MCRAccessManager.PERMISSION_READ)) {
MCRAccessKeyUtils.removeAccessKeySecretFromCurrentSession(objectId);
}
}
}
final String userSecret = MCRAccessKeyUtils.getAccessKeySecretFromCurrentUser(objectId);
if (userSecret != null) {
final MCRAccessKey accessKey = MCRAccessKeyManager.getAccessKeyWithSecret(objectId, userSecret);
if (accessKey != null) {
LOGGER.debug("Found match in access key strategy for {} on {} for user.", permission, objectId);
if (MCRAccessKeyStrategyHelper.verifyAccessKey(permission, accessKey)) {
return true;
}
}
if (accessKey == null || permission.equals(MCRAccessManager.PERMISSION_READ)) {
MCRAccessKeyUtils.removeAccessKeySecretFromCurrentUser(objectId);
}
}
}
return false;
}

private boolean checkObjectPermission(MCRObjectID objectId, String permission) {
LOGGER.debug("checkObjectPermission({}, {})", objectId, permission);

Expand All @@ -146,9 +107,8 @@ private boolean checkObjectPermission(MCRObjectID objectId, String permission) {

String permissionId = objectId.toString();

// 2. check read or write key of current user
if (MCRAccessKeyUtils.isAccessKeyForObjectTypeAllowed(objectId.getTypeId())
&& hasValidAccessKey(objectId, permission)) {
// 2. check read or write key
if (ACCESS_KEY_OBJECT_STRATEGY.checkObjectPermission(objectId, permission)) {
return true;
}

Expand Down Expand Up @@ -212,11 +172,9 @@ private boolean checkDerivatePermission(MCRObjectID derivateId, String permissio
}
}

// 2. check read or write key of current user
if ((MCRAccessKeyUtils.isAccessKeyForObjectTypeAllowed(objectId.getTypeId())
&& hasValidAccessKey(objectId, permission))
|| (MCRAccessKeyUtils.isAccessKeyForObjectTypeAllowed(derivateId.getTypeId())
&& hasValidAccessKey(derivateId, permission))) {
// 2. check read or write key
if (ACCESS_KEY_OBJECT_STRATEGY.checkObjectPermission(objectId, permission)
|| ACCESS_KEY_OBJECT_STRATEGY.checkObjectPermission(derivateId, permission)) {
return true;
}

Expand Down Expand Up @@ -267,12 +225,12 @@ private boolean canEditPI() {

private Optional<MCRCategoryID> getAccessCategory(MCRObjectID objectId, MCRObjectID derivateId, String permission) {
String type = Stream.of(derivateId, objectId).filter(Objects::nonNull).map(MCRObjectID::getTypeId).findFirst()
.get();
.get();
List<MCRCategoryID> amc = getAccessMappedCategories(type, permission, accessClasses);
return Stream.of(derivateId, objectId)
.filter(Objects::nonNull)
.flatMap(id -> getAccessCategory(amc, id).stream())
.findFirst();
.filter(Objects::nonNull)
.flatMap(id -> getAccessCategory(amc, id).stream())
.findFirst();
}

private Optional<MCRCategoryID> getAccessCategory(List<MCRCategoryID> accessMappedCategories, MCRObjectID id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
import org.jdom2.Element;
import org.mycore.common.MCRSessionMgr;
import org.mycore.common.MCRSystemUserInformation;
import org.mycore.common.MCRUserInformation;
import org.mycore.datamodel.metadata.MCRObjectID;
import org.mycore.frontend.servlets.MCRServlet;
import org.mycore.frontend.servlets.MCRServletJob;
import org.mycore.mcr.acl.accesskey.MCRAccessKeyUtils;
import org.mycore.mcr.acl.accesskey.config.MCRAccessKeyConfig;
import org.mycore.mcr.acl.accesskey.exception.MCRAccessKeyException;
import org.mycore.mcr.acl.accesskey.service.MCRAccessKeyServiceFactory;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand All @@ -38,59 +38,64 @@ public class MIRAccessKeyServlet extends MCRServlet {

private static final long serialVersionUID = 1L;

private static final String REDIRECT_URL_PARAMETER = "url";
private static final String QUERY_PARAM_ACTION = "action";

private static String getReturnURL(HttpServletRequest req) {
String returnURL = req.getParameter(REDIRECT_URL_PARAMETER);
if (returnURL == null) {
String referer = req.getHeader("Referer");
returnURL = (referer != null) ? referer : req.getContextPath() + "/";
}
return returnURL;
}
private static final String QUERY_PARAM_OBJ_ID = "objId";

private static final String QUERY_PARAM_REDIRECT_URL = "url";

/* (non-Javadoc)
* @see org.mycore.frontend.servlets.MCRServlet#doGetPost(org.mycore.frontend.servlets.MCRServletJob)
*/
@Override
protected void doGetPost(MCRServletJob job) throws Exception {
HttpServletRequest req = job.getRequest();
HttpServletResponse res = job.getResponse();
final MCRUserInformation userInfo = MCRSessionMgr.getCurrentSession().getUserInformation();
final boolean isGuest = userInfo.getUserID().equals(MCRSystemUserInformation.getGuestInstance().getUserID());
if (isGuest && !MCRAccessKeyUtils.isAccessKeyForSessionAllowed()) {
final HttpServletRequest req = job.getRequest();
final HttpServletResponse res = job.getResponse();
final boolean isGuest = checkCurrentUserIsGuest();
if (isGuest && MCRAccessKeyConfig.getAllowedSessionPermissionTypes().isEmpty()) {
res.sendError(HttpServletResponse.SC_FORBIDDEN, "Access can only be granted to personalized users");
return;
}
final Document doc = (Document) (job.getRequest().getAttribute("MCRXEditorSubmission"));
if (doc == null) {
if (doc == null || req.getParameter(QUERY_PARAM_ACTION) != null) {
res.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
final String action = req.getParameter("action");
final Element xml = doc.getRootElement();
final String objId = xml.getAttributeValue("objId");
final MCRObjectID mcrObjId = MCRObjectID.getInstance(objId);
if (action == null) {
final String value = xml.getTextTrim();
if (value == null || value.length() == 0) {
res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing documentID or accessKey parameter");
return;
}
try {
if (isGuest) {
MCRAccessKeyUtils.addAccessKeySecretToCurrentSession(mcrObjId, value);
} else {
MCRAccessKeyUtils.addAccessKeySecretToCurrentUser(mcrObjId, value);
}
} catch(MCRAccessKeyException e) {
res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Access key is unknown or not allowed.");
return;
}
} else {
final String objId = xml.getAttributeValue(QUERY_PARAM_OBJ_ID);
if (objId == null || !MCRObjectID.isValid(objId)) {
res.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
final String value = xml.getTextTrim();
if (value.isEmpty()) {
res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing documentID or accessKey parameter");
return;
}
try {
if (isGuest) {
MCRAccessKeyServiceFactory.getAccessKeySessionService().activateAccessKey(objId, value);
} else {
MCRAccessKeyServiceFactory.getAccessKeyUserService().activateAccessKey(objId, value);
}
} catch (MCRAccessKeyException e) {
res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Access key is unknown or not allowed.");
return;
}
res.sendRedirect(getReturnURL(req));
}

private static boolean checkCurrentUserIsGuest() {
return MCRSessionMgr.getCurrentSession().getUserInformation().getUserID()
.equals(MCRSystemUserInformation.getGuestInstance().getUserID());
}

private static String getReturnURL(HttpServletRequest req) {
String returnURL = req.getParameter(QUERY_PARAM_REDIRECT_URL);
if (returnURL == null) {
String referer = req.getHeader("Referer");
returnURL = (referer != null) ? referer : req.getContextPath() + "/";
}
return returnURL;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@
import org.mycore.datamodel.metadata.MCRObjectID;
import org.mycore.frontend.cli.MCRCommandLineInterface;
import org.mycore.frontend.cli.MCRCommandManager;
import org.mycore.mcr.acl.accesskey.MCRAccessKeyManager;
import org.mycore.mcr.acl.accesskey.MCRAccessKeyUtils;
import org.mycore.mcr.acl.accesskey.model.MCRAccessKey;
import org.mycore.mcr.acl.accesskey.dto.MCRAccessKeyDto;
import org.mycore.mcr.acl.accesskey.service.MCRAccessKeyServiceFactory;
import org.mycore.user2.MCRUser;
import org.mycore.user2.MCRUserManager;

Expand All @@ -48,6 +47,7 @@ public class MIRStrategyTest extends MCRJPATestCase {

Path localTestDirectory;

@Override
@Before
public void setUp() throws Exception {
super.setUp();
Expand Down Expand Up @@ -87,6 +87,7 @@ private void executeCommands(List<String> cmds) throws Exception {
}
}

@Override
@After
public void tearDown() throws Exception {
final Collection<String> allControlledIDs = MCRAccessManager.requireRulesInterface().getAllControlledIDs();
Expand Down Expand Up @@ -166,10 +167,17 @@ public void checkAccessKeyPermission() throws Exception {
Assert
.assertFalse(strategy.checkPermission(mir_derivate_00004711.toString(), MCRAccessManager.PERMISSION_WRITE));

final MCRAccessKey accessKeyRead = new MCRAccessKey("mySecret", MCRAccessManager.PERMISSION_READ);
MCRAccessKeyManager.createAccessKey(mir_mods_00004711, accessKeyRead);
final MCRAccessKey accessKeyWrite = new MCRAccessKey("letMeIn", MCRAccessManager.PERMISSION_WRITE);
MCRAccessKeyManager.createAccessKey(mir_mods_00004711, accessKeyWrite);
final MCRAccessKeyDto accessKeyRead = new MCRAccessKeyDto();
accessKeyRead.setSecret("mySecret");
accessKeyRead.setPermission(MCRAccessManager.PERMISSION_READ);
accessKeyRead.setReference(mir_mods_00004711.toString());
MCRAccessKeyServiceFactory.getAccessKeyService().addAccessKey(accessKeyRead);

final MCRAccessKeyDto accessKeyWrite = new MCRAccessKeyDto();
accessKeyWrite.setSecret("letMeIn");
accessKeyWrite.setPermission(MCRAccessManager.PERMISSION_WRITE);
accessKeyWrite.setReference(mir_mods_00004711.toString());
MCRAccessKeyServiceFactory.getAccessKeyService().addAccessKey(accessKeyWrite);

final MCRCategLinkService categLinkService = MCRCategLinkServiceFactory.getInstance();
MCRCategLinkReference ref = new MCRCategLinkReference(mir_mods_00004711);
Expand All @@ -180,7 +188,8 @@ public void checkAccessKeyPermission() throws Exception {
.assertFalse(strategy.checkPermission(mir_derivate_00004711.toString(), MCRAccessManager.PERMISSION_READ));

//Give user read access-token
MCRAccessKeyUtils.addAccessKeySecretToCurrentUser(mir_mods_00004711, "mySecret");
MCRAccessKeyServiceFactory.getAccessKeyUserService()
.activateAccessKey(mir_mods_00004711.toString(), "mySecret");
junitUser = MCRUserManager.getUser(junitUser.getUserName());
MCRSessionMgr.getCurrentSession().setUserInformation(junitUser);

Expand All @@ -193,7 +202,8 @@ public void checkAccessKeyPermission() throws Exception {
assertTrue(strategy.checkPermission(mir_mods_00004711.toString(), MCRAccessManager.PERMISSION_PREVIEW));

//Give user write access-token
MCRAccessKeyUtils.addAccessKeySecretToCurrentUser(mir_mods_00004711, "letMeIn");
MCRAccessKeyServiceFactory.getAccessKeyUserService().activateAccessKey(
mir_mods_00004711.toString(), "letMeIn");
junitUser = MCRUserManager.getUser(junitUser.getUserName());
MCRSessionMgr.getCurrentSession().setUserInformation(junitUser);

Expand Down
Loading