/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program 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 * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package org.codice.ddf.catalog.ui.security; import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.codice.ddf.catalog.ui.metacard.workspace.WorkspaceMetacardImpl; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import ddf.catalog.data.Metacard; import ddf.catalog.operation.CreateRequest; import ddf.catalog.operation.DeleteRequest; import ddf.catalog.operation.DeleteResponse; import ddf.catalog.operation.QueryRequest; import ddf.catalog.operation.QueryResponse; import ddf.catalog.operation.ResourceRequest; import ddf.catalog.operation.ResourceResponse; import ddf.catalog.operation.UpdateRequest; import ddf.catalog.plugin.AccessPlugin; import ddf.catalog.plugin.StopProcessingException; import ddf.security.permission.CollectionPermission; import ddf.security.permission.KeyValueCollectionPermission; public class WorkspaceAccessPlugin implements AccessPlugin { protected Subject getSubject() { return SecurityUtils.getSubject(); } private KeyValueCollectionPermission isOwnerPermission(String owner) { Map<String, Set<String>> securityAttributes = ImmutableMap.of(Constants.EMAIL_ADDRESS_CLAIM_URI, ImmutableSet.of(owner)); return new KeyValueCollectionPermission(CollectionPermission.UPDATE_ACTION, securityAttributes); } private boolean isSharingUpdated(WorkspaceMetacardImpl previous, WorkspaceMetacardImpl update) { return !update.diffSharing(previous) .isEmpty(); } private boolean isNotOwner(String owner) { return !getSubject().isPermitted(isOwnerPermission(owner)); } @Override public CreateRequest processPreCreate(CreateRequest input) throws StopProcessingException { return input; } @Override public UpdateRequest processPreUpdate(UpdateRequest input, Map<String, Metacard> existingMetacards) throws StopProcessingException { Function<WorkspaceMetacardImpl, WorkspaceMetacardImpl> previous = (update) -> WorkspaceMetacardImpl.from(existingMetacards.get(update.getId())); Set<String> notOwners = input.getUpdates() .stream() .map(Map.Entry::getValue) .filter(WorkspaceMetacardImpl::isWorkspaceMetacard) .map(WorkspaceMetacardImpl::from) .filter(update -> isSharingUpdated(previous.apply(update), update)) .map(previous) .map(WorkspaceMetacardImpl::getOwner) .filter(this::isNotOwner) .collect(Collectors.toSet()); if (!notOwners.isEmpty()) { throw new StopProcessingException( "Cannot update workspace. Subject cannot change sharing permissions because they are not the owner."); } return input; } @Override public DeleteRequest processPreDelete(DeleteRequest input) throws StopProcessingException { return input; } @Override public DeleteResponse processPostDelete(DeleteResponse input) throws StopProcessingException { return input; } @Override public QueryRequest processPreQuery(QueryRequest input) throws StopProcessingException { return input; } @Override public QueryResponse processPostQuery(QueryResponse input) throws StopProcessingException { return input; } @Override public ResourceRequest processPreResource(ResourceRequest input) throws StopProcessingException { return input; } @Override public ResourceResponse processPostResource(ResourceResponse input, Metacard metacard) throws StopProcessingException { return input; } }