Skip to content

Commit

Permalink
Implement adding ACLs (fcrepo#1672)
Browse files Browse the repository at this point in the history
* Implement adding ACLs
  • Loading branch information
whikloj authored May 4, 2020
1 parent 437bc71 commit 8310f77
Show file tree
Hide file tree
Showing 18 changed files with 292 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@
import org.fcrepo.kernel.api.models.WebacAcl;
import org.fcrepo.kernel.api.rdf.DefaultRdfStream;
import org.fcrepo.kernel.api.rdf.RdfNamespaceRegistry;
import org.fcrepo.kernel.api.services.CreateResourceService;
import org.fcrepo.kernel.api.services.DeleteResourceService;
import org.fcrepo.kernel.api.services.ManagedPropertiesService;
import org.fcrepo.kernel.api.services.ReplacePropertiesService;
import org.fcrepo.kernel.api.services.UpdatePropertiesService;
Expand Down Expand Up @@ -222,6 +224,12 @@ public abstract class ContentExposingResource extends FedoraBaseResource {
@Inject
protected RdfNamespaceRegistry namespaceRegistry;

@Inject
protected CreateResourceService createResourceService;

@Inject
protected DeleteResourceService deleteResourceService;

@Inject
protected ReplacePropertiesService replacePropertiesService;

Expand Down
95 changes: 46 additions & 49 deletions fcrepo-http-api/src/main/java/org/fcrepo/http/api/FedoraAcl.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@
import static org.fcrepo.http.commons.domain.RDFMediaType.TEXT_PLAIN_WITH_CHARSET;
import static org.fcrepo.http.commons.domain.RDFMediaType.TURTLE_WITH_CHARSET;
import static org.fcrepo.http.commons.domain.RDFMediaType.TURTLE_X;
import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_REPOSITORY_ROOT;
import static org.fcrepo.kernel.api.FedoraTypes.FCR_ACL;
import static org.slf4j.LoggerFactory.getLogger;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;

import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.BadRequestException;
Expand Down Expand Up @@ -74,11 +74,12 @@
import org.fcrepo.kernel.api.RdfStream;
import org.fcrepo.kernel.api.exception.AccessDeniedException;
import org.fcrepo.kernel.api.exception.ItemNotFoundException;
import org.fcrepo.kernel.api.exception.PathNotFoundException;
import org.fcrepo.kernel.api.exception.PathNotFoundRuntimeException;
import org.fcrepo.kernel.api.identifiers.FedoraId;
import org.fcrepo.kernel.api.models.FedoraResource;
import org.fcrepo.kernel.api.models.WebacAcl;
import org.fcrepo.kernel.api.rdf.DefaultRdfStream;
import org.fcrepo.kernel.api.services.DeleteResourceService;
import org.fcrepo.kernel.api.services.WebacAclService;
import org.slf4j.Logger;
import org.springframework.context.annotation.Scope;
Expand All @@ -104,9 +105,6 @@ public class FedoraAcl extends ContentExposingResource {

@PathParam("path") protected String externalPath;

@Inject
private DeleteResourceService deleteResourceService;

@Inject
private WebacAclService webacAclService;

Expand All @@ -130,37 +128,32 @@ public Response createFedoraWebacAcl(@HeaderParam(CONTENT_TYPE) final MediaType
if (resource().isAcl() || resource().isMemento()) {
throw new BadRequestException("ACL resource creation is not allowed for resource " + resource().getId());
}
LOGGER.info("PUT acl resource '{}'", externalPath());

final boolean created;
final FedoraResource aclResource;

final String path = toPath(translator(), externalPath);
LOGGER.info("PUT acl resource '{}'", externalPath);

final var transaction = transaction();

aclResource = webacAclService.findOrCreate(transaction, path);
created = aclResource.isNew();
final FedoraId aclId = aclResource.getFedoraId();
final FedoraId aclId = identifierConverter().pathToInternalId(externalPath()).resolve(FCR_ACL);
final boolean exists = resourceFactory.doesResourceExist(transaction(), aclId);

final MediaType contentType =
requestContentType == null ? RDFMediaType.TURTLE_TYPE : valueOf(getSimpleContentType(requestContentType));
if (isRdfContentType(contentType.toString())) {

// TODO: confirm this is correct logic for ACL's
final Model model = httpRdfService.bodyToInternalModel(externalPath() + "/fcr:acl",
requestBodyStream, requestContentType, identifierConverter());

replacePropertiesService.perform(transaction.getId(), getUserPrincipal(), aclId, model);
final Model model = httpRdfService.bodyToInternalModel(aclId.getFullId(),
requestBodyStream, contentType, identifierConverter());
if (exists) {
replacePropertiesService.perform(transaction().getId(), getUserPrincipal(), aclId, model);
} else {
webacAclService.create(transaction(), aclId, getUserPrincipal(), model);
}
} else {
throw new BadRequestException("Content-Type (" + requestContentType + ") is invalid. Try text/turtle " +
"or other RDF compatible type.");
}
transaction.commit();
transaction().commitIfShortLived();

addCacheControlHeaders(servletResponse, aclResource, transaction);
final FedoraResource aclResource = getFedoraResource(transaction(), aclId);
addCacheControlHeaders(servletResponse, aclResource, transaction());
final URI location = getUri(aclResource);
if (created) {
if (!exists) {
return created(location).build();
} else {
return noContent().location(location).build();
Expand All @@ -184,15 +177,17 @@ public Response updateSparql(final InputStream requestBodyStream)
throw new BadRequestException("SPARQL-UPDATE requests must have content!");
}

final FedoraResource aclResource = resource().getAcl();

if (aclResource == null) {
if (resource().hasType(FEDORA_REPOSITORY_ROOT)) {
final FedoraId originalId = identifierConverter().pathToInternalId(externalPath());
final FedoraId aclId = originalId.resolve(FCR_ACL);
final FedoraResource aclResource;
try {
aclResource = resourceFactory.getResource(transaction(), aclId);
} catch (final PathNotFoundException exc) {
if (originalId.isRepositoryRoot()) {
throw new ClientErrorException("The default root ACL is system generated and cannot be modified. " +
"To override the default root ACL you must PUT a user-defined ACL to this endpoint.",
CONFLICT);
}

throw new ItemNotFoundException("not found");
}

Expand All @@ -206,7 +201,7 @@ public Response updateSparql(final InputStream requestBodyStream)

LOGGER.info("PATCH for '{}'", externalPath);
patchResourcewithSparql(aclResource, requestBody);
transaction().commit();
transaction().commitIfShortLived();

addCacheControlHeaders(servletResponse, aclResource, transaction());

Expand Down Expand Up @@ -243,25 +238,29 @@ protected String externalPath() {
public Response getResource()
throws IOException, ItemNotFoundException {

LOGGER.info("GET resource '{}'", externalPath);
LOGGER.info("GET resource '{}'", externalPath());

final FedoraResource aclResource = resource().getAcl();
final FedoraId originalId = identifierConverter().pathToInternalId(externalPath());
final FedoraId aclId = originalId.resolve(FCR_ACL);
final boolean exists = resourceFactory.doesResourceExist(transaction(), aclId);

if (aclResource == null) {
if (resource().hasType(FEDORA_REPOSITORY_ROOT)) {
final String resourceUri = getUri(resource()).toString();
final String aclUri = resourceUri + (resourceUri.endsWith("/") ? "" : "/") + FCR_ACL;
if (!exists) {
if (originalId.isRepositoryRoot()) {
final String aclUri = identifierConverter().toExternalId(aclId.getFullId());

final RdfStream defaultRdfStream = DefaultRdfStream.fromModel(createResource(aclUri).asNode(),
getDefaultAcl(aclUri));
final RdfNamespacedStream output = new RdfNamespacedStream(defaultRdfStream,
namespaceRegistry.getNamespaces());
final RdfStream rdfStream = httpRdfService.bodyToExternalStream(aclUri,
defaultRdfStream, identifierConverter());
final var output = new RdfNamespacedStream(
rdfStream, namespaceRegistry.getNamespaces());
return ok(output).build();
}

throw new ItemNotFoundException(String.format("No ACL found at %s", externalPath));
}

final WebacAcl aclResource = webacAclService.find(transaction(), aclId);
checkCacheControlHeaders(request, servletResponse, aclResource, transaction());

LOGGER.info("GET resource '{}'", externalPath);
Expand All @@ -281,24 +280,22 @@ public Response deleteObject() throws ItemNotFoundException {
hasRestrictedPath(externalPath);
LOGGER.info("Delete resource '{}'", externalPath);

final FedoraResource aclResource = resource().getAcl();
if (aclResource != null) {
final FedoraId originalId = identifierConverter().pathToInternalId(externalPath());
final FedoraId aclId = originalId.resolve(FCR_ACL);
try {
final var aclResource = resourceFactory.getResource(transaction(), aclId);
deleteResourceService.perform(transaction(), aclResource, getUserPrincipal());
}
transaction().commit();

if (aclResource == null) {
if (resource().hasType(FEDORA_REPOSITORY_ROOT)) {
} catch (final PathNotFoundException exc) {
if (originalId.isRepositoryRoot()) {
throw new ClientErrorException("The default root ACL is system generated and cannot be deleted. " +
"To override the default root ACL you must PUT a user-defined ACL to this endpoint.",
CONFLICT);
}

throw new ItemNotFoundException("not found");
throw new PathNotFoundRuntimeException(exc);
} finally {
transaction().commitIfShortLived();
}

return noContent().build();

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,6 @@
import org.fcrepo.kernel.api.models.ExternalContent;
import org.fcrepo.kernel.api.models.FedoraResource;
import org.fcrepo.kernel.api.models.NonRdfSourceDescription;
import org.fcrepo.kernel.api.services.CreateResourceService;
import org.fcrepo.kernel.api.services.DeleteResourceService;
import org.fcrepo.kernel.api.services.FixityService;
import org.fcrepo.kernel.api.services.ReplaceBinariesService;
import org.fcrepo.kernel.api.utils.ContentDigest;
Expand Down Expand Up @@ -149,12 +147,6 @@ public class FedoraLdp extends ContentExposingResource {
@Inject
private FedoraHttpConfiguration httpConfiguration;

@Inject
private CreateResourceService createResourceService;

@Inject
private DeleteResourceService deleteResourceService;

@Inject
protected ReplaceBinariesService replaceBinariesService;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
import org.apache.jena.sparql.core.DatasetGraph;
import org.fcrepo.http.commons.test.util.CloseableDataset;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.RestoreSystemProperties;
Expand All @@ -76,7 +75,6 @@ public void init() {
subjectUri = serverAddress + id;
}

@Ignore //TODO Fix this test
@Test
public void testCreateAclWithoutBody() throws Exception {
createObjectAndClose(id);
Expand All @@ -91,7 +89,6 @@ public void testCreateAclWithoutBody() throws Exception {
}
}

@Ignore //TODO Fix this test
@Test
public void testCreateAclOnAclResource() throws Exception {
createObjectAndClose(id);
Expand All @@ -111,7 +108,6 @@ private String createACL() throws IOException {
}
}

@Ignore //TODO Fix this test
@Test
public void testCreateAclOnBinary() throws Exception {
createDatastream(id, "x", "some content");
Expand All @@ -134,7 +130,6 @@ public void testCreateAclOnBinary() throws Exception {
}
}

@Ignore //TODO Fix this test
@Test
public void testPatchAcl() throws Exception {
createObjectAndClose(id);
Expand All @@ -156,7 +151,6 @@ public void testPatchAcl() throws Exception {

}

@Ignore //TODO Fix this test
@Test
public void testCreateAndRetrieveAcl() throws Exception {
createObjectAndClose(id);
Expand All @@ -175,7 +169,6 @@ public void testCreateAndRetrieveAcl() throws Exception {

}

@Ignore //TODO Fix this test
@Test
public void testPutACLBadRdf() throws IOException {
createObjectAndClose(id);
Expand All @@ -186,7 +179,6 @@ public void testPutACLBadRdf() throws IOException {
assertEquals(BAD_REQUEST.getStatusCode(), getStatus(put));
}

@Ignore //TODO Fix this test
@Test
public void testDeleteAcl() throws Exception {
createObjectAndClose(id);
Expand Down Expand Up @@ -219,11 +211,10 @@ public void testGetNonExistentAcl() {

}

@Ignore //TODO Fix this test
@Test
public void testGetDefaultRootAcl() throws Exception {
final String rootAclUri = serverAddress + FCR_ACL;
final String rootFedoraUri = "info:fedora/";
final String rootFedoraUri = serverAddress;
final String authzUri = rootFedoraUri + FCR_ACL + "#authz";
try (final CloseableDataset dataset = getDataset(new HttpGet(rootAclUri))) {
final DatasetGraph graph = dataset.asDatasetGraph();
Expand All @@ -249,23 +240,20 @@ public void testGetDefaultRootAcl() throws Exception {
}
}

@Ignore //TODO Fix this test
@Test
public void testDeleteDefaultRootAcl() {
final String rootAclUri = serverAddress + FCR_ACL;
assertEquals("DELETE should fail for default generated root ACL.",
CONFLICT.getStatusCode(), getStatus(new HttpDelete(rootAclUri)));
}

@Ignore //TODO Fix this test
@Test
public void testPatchDefaultRootAcl() {
final String rootAclUri = serverAddress + FCR_ACL;
assertEquals("PATCH should fail for default generated root ACL.",
CONFLICT.getStatusCode(), getStatus(new HttpPatch(rootAclUri)));
}

@Ignore //TODO Fix this test
@Test
public void testGetUserDefinedDefaultRootAcl() throws Exception {
System.setProperty(ROOT_AUTHORIZATION_PROPERTY, "./target/test-classes/test-root-authorization.ttl");
Expand All @@ -284,7 +272,6 @@ public void testGetUserDefinedDefaultRootAcl() throws Exception {
}
}

@Ignore //TODO Fix this test
@Test
public void testAddModifyDeleteUserDefinedDefaultRootAcl() throws Exception {
final String rootAclUri = serverAddress + FCR_ACL;
Expand Down Expand Up @@ -316,7 +303,6 @@ public void testAddModifyDeleteUserDefinedDefaultRootAcl() throws Exception {
NO_CONTENT.getStatusCode(), getStatus(new HttpDelete(rootAclUri)));
}

@Ignore //TODO Fix this test
@Test
public void testCreateAclWithBody() throws Exception {
createObjectAndClose(id);
Expand Down Expand Up @@ -352,7 +338,6 @@ public void testCreateAclWithBody() throws Exception {

}

@Ignore //TODO Fix this test
@Test
public void testCreateAclWithoutAccessToSetsDefaultTarget() throws Exception {
createObjectAndClose(id);
Expand Down Expand Up @@ -387,7 +372,6 @@ public void testCreateAclWithoutAccessToSetsDefaultTarget() throws Exception {

}

@Ignore //TODO Fix this test
@Test
public void testCreateAclWithAccessTo() throws Exception {
createObjectAndClose(id);
Expand Down Expand Up @@ -433,7 +417,6 @@ public void testCreateAclWithAccessTo() throws Exception {
}
}

@Ignore //TODO Fix this test
@Test
public void testCreateAclWithAccessToClass() throws Exception {
createObjectAndClose(id);
Expand Down Expand Up @@ -479,7 +462,6 @@ public void testCreateAclWithAccessToClass() throws Exception {
}
}

@Ignore //TODO Fix this test
@Test
public void testCreateAclWithBothAccessToandAccessToClassIsNotAllowed() throws Exception {
createObjectAndClose(id);
Expand Down
Loading

0 comments on commit 8310f77

Please sign in to comment.