/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE file at the root of the source
* tree and available online at
*
* https://github.com/keeps/roda
*/
package org.roda.core.plugins.plugins.ingest;
import java.util.Arrays;
import java.util.List;
import org.roda.core.common.UserUtility;
import org.roda.core.data.common.RodaConstants;
import org.roda.core.data.common.RodaConstants.PreservationEventType;
import org.roda.core.data.exceptions.AlreadyExistsException;
import org.roda.core.data.exceptions.AuthorizationDeniedException;
import org.roda.core.data.exceptions.GenericException;
import org.roda.core.data.exceptions.NotFoundException;
import org.roda.core.data.exceptions.RequestNotValidException;
import org.roda.core.data.v2.LiteOptionalWithCause;
import org.roda.core.data.v2.ip.AIP;
import org.roda.core.data.v2.ip.AIPState;
import org.roda.core.data.v2.ip.IndexedAIP;
import org.roda.core.data.v2.ip.Permissions.PermissionType;
import org.roda.core.data.v2.jobs.Job;
import org.roda.core.data.v2.jobs.PluginType;
import org.roda.core.data.v2.jobs.Report;
import org.roda.core.data.v2.jobs.Report.PluginState;
import org.roda.core.data.v2.user.RODAMember;
import org.roda.core.data.v2.user.User;
import org.roda.core.data.v2.validation.ValidationException;
import org.roda.core.index.IndexService;
import org.roda.core.model.ModelService;
import org.roda.core.plugins.AbstractPlugin;
import org.roda.core.plugins.Plugin;
import org.roda.core.plugins.PluginException;
import org.roda.core.plugins.RODAObjectProcessingLogic;
import org.roda.core.plugins.orchestrate.SimpleJobPluginInfo;
import org.roda.core.plugins.plugins.PluginHelper;
import org.roda.core.storage.StorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyUserAuthorizationPlugin extends AbstractPlugin<AIP> {
private static final Logger LOGGER = LoggerFactory.getLogger(VerifyUserAuthorizationPlugin.class);
private static final String PARENT_AIP_NOT_FOUND = "The parent of the AIP was not found";
private static final List<String> userFieldsToReturn = Arrays.asList(RodaConstants.MEMBERS_GROUPS,
RodaConstants.MEMBERS_ID);
private boolean hasFreeAccess = false;
@Override
public void init() throws PluginException {
// do nothing
}
@Override
public void shutdown() {
// do nothing
}
public static String getStaticName() {
return "Verify user authorization";
}
@Override
public String getName() {
return getStaticName();
}
public static String getStaticDescription() {
return "Checks if the user has enough permissions to place the AIP under the desired node in the classification scheme";
}
@Override
public String getDescription() {
return getStaticDescription();
}
@Override
public String getVersionImpl() {
return "1.0";
}
@Override
public Report execute(IndexService index, ModelService model, StorageService storage,
List<LiteOptionalWithCause> liteList) throws PluginException {
return PluginHelper.processObjects(this, new RODAObjectProcessingLogic<AIP>() {
@Override
public void process(IndexService index, ModelService model, StorageService storage, Report report, Job cachedJob,
SimpleJobPluginInfo jobPluginInfo, Plugin<AIP> plugin, AIP object) {
processAIP(index, model, report, cachedJob, jobPluginInfo, object);
}
}, index, model, storage, liteList);
}
private void processAIP(IndexService index, ModelService model, Report report, Job currentJob,
SimpleJobPluginInfo jobPluginInfo, AIP aip) {
LOGGER.debug("Checking producer authorization for AIPingest.submitP {}", aip.getId());
Report reportItem = PluginHelper.initPluginReportItem(this, aip.getId(), AIP.class, AIPState.INGEST_PROCESSING);
PluginHelper.updatePartialJobReport(this, model, reportItem, false, currentJob);
reportItem.setPluginState(PluginState.SUCCESS)
.setPluginDetails(String.format("Done with checking producer authorization for AIP %s", aip.getId()));
if (currentJob != null) {
processAIPPermissions(index, currentJob, aip, reportItem);
} else {
reportItem.setPluginState(PluginState.FAILURE).setPluginDetails("Unable to determine Job.");
}
try {
boolean notify = true;
PluginHelper.createPluginEvent(this, aip.getId(), model, index, reportItem.getPluginState(),
reportItem.getPluginDetails(), notify);
} catch (RequestNotValidException | NotFoundException | GenericException | AuthorizationDeniedException
| ValidationException | AlreadyExistsException e) {
reportItem.setPluginState(PluginState.FAILURE).addPluginDetails("Unable to create event.");
}
// set counters
if (reportItem.getPluginState() == PluginState.SUCCESS) {
jobPluginInfo.incrementObjectsProcessedWithSuccess();
} else {
jobPluginInfo.incrementObjectsProcessedWithFailure();
}
LOGGER.debug("Done with checking producer authorization for AIP {}", aip.getId());
report.addReport(reportItem);
PluginHelper.updatePartialJobReport(this, model, reportItem, true, currentJob);
}
private void processAIPPermissions(IndexService index, Job currentJob, AIP aip, Report reportItem) {
try {
String jobCreatorUsername = currentJob.getUsername();
if (aip.getParentId() != null) {
try {
IndexedAIP parentAIP = index.retrieve(IndexedAIP.class, aip.getParentId(),
RodaConstants.AIP_PERMISSIONS_FIELDS_TO_RETURN);
User user = index.retrieve(User.class, jobCreatorUsername, userFieldsToReturn);
UserUtility.checkAIPPermissions(user, parentAIP, PermissionType.CREATE);
} catch (NotFoundException nfe) {
reportItem.setPluginState(PluginState.FAILURE).setPluginDetails(PARENT_AIP_NOT_FOUND);
} catch (AuthorizationDeniedException e) {
LOGGER.debug("User '{}' doesn't have CREATE permission on parent... Error...", jobCreatorUsername);
reportItem.setPluginState(PluginState.FAILURE).setPluginDetails(
"The user " + jobCreatorUsername + " doesn't have permission to create under AIP " + aip.getId());
}
} else {
RODAMember member = index.retrieve(RODAMember.class, jobCreatorUsername,
Arrays.asList(RodaConstants.MEMBERS_ROLES_ALL));
if (member.getAllRoles().contains(RodaConstants.REPOSITORY_PERMISSIONS_AIP_CREATE_TOP)) {
LOGGER.debug("User have CREATE_TOP_LEVEL_AIP_PERMISSION permission.");
} else {
reportItem.setPluginState(PluginState.FAILURE).setPluginDetails(
"The user " + jobCreatorUsername + " doesn't have CREATE_TOP_LEVEL_AIP_PERMISSION permission");
LOGGER.debug("User doesn't have CREATE_TOP_LEVEL_AIP_PERMISSION permission...");
}
}
} catch (GenericException | NotFoundException e) {
reportItem.setPluginState(PluginState.FAILURE).setPluginDetails(e.getMessage());
}
}
@Override
public Plugin<AIP> cloneMe() {
return new VerifyUserAuthorizationPlugin();
}
@Override
public PluginType getType() {
return PluginType.AIP_TO_AIP;
}
@Override
public boolean areParameterValuesValid() {
return true;
}
@Override
public PreservationEventType getPreservationEventType() {
return PreservationEventType.AUTHORIZATION_CHECK;
}
@Override
public String getPreservationEventDescription() {
String description = "Producer permissions have been checked to ensure that he has sufficient authorization to store the AIP under the desired "
+ "node of the classification scheme.";
if (hasFreeAccess) {
description += " It was given READ permission to the users group as indicated on the descriptive metadata";
}
return description;
}
@Override
public String getPreservationEventSuccessMessage() {
return "The producer has enough permissions to deposit the AIP under the designated node of the classification scheme";
}
@Override
public String getPreservationEventFailureMessage() {
return "The producer does not have enough permissions to deposit the AIP under the designated node of the classification scheme";
}
@Override
public Report beforeAllExecute(IndexService index, ModelService model, StorageService storage)
throws PluginException {
// do nothing
return null;
}
@Override
public Report afterAllExecute(IndexService index, ModelService model, StorageService storage) throws PluginException {
// do nothing
return null;
}
@Override
public List<String> getCategories() {
return Arrays.asList(RodaConstants.PLUGIN_CATEGORY_NOT_LISTABLE);
}
@Override
public List<Class<AIP>> getObjectClasses() {
return Arrays.asList(AIP.class);
}
}