package eu.europeana.cloud.service.mcs.rest;
import eu.europeana.cloud.common.model.Representation;
import eu.europeana.cloud.service.commons.permissions.PermissionsGrantingManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import org.springframework.stereotype.Component;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Arrays;
import java.util.List;
import static eu.europeana.cloud.common.web.AASParamConstants.P_PERMISSION;
import static eu.europeana.cloud.common.web.AASParamConstants.P_USER_NAME;
import static eu.europeana.cloud.common.web.ParamConstants.*;
/**
* Resource to authorize other users to read specific versions.
*/
@Path("/records/{" + P_CLOUDID + "}/representations/{" + P_REPRESENTATIONNAME + "}/versions/{" + P_VER + "}")
@Component
public class RepresentationAuthorizationResource {
private static final List<String> acceptedPermissionValues
= Arrays.asList(
eu.europeana.cloud.common.model.Permission.ALL.getValue(),
eu.europeana.cloud.common.model.Permission.READ.getValue(),
eu.europeana.cloud.common.model.Permission.WRITE.getValue(),
eu.europeana.cloud.common.model.Permission.ADMINISTRATION.getValue(),
eu.europeana.cloud.common.model.Permission.DELETE.getValue());
@Autowired
private MutableAclService mutableAclService;
@Autowired
private PermissionsGrantingManager permissionsGrantingManager;
private final String REPRESENTATION_CLASS_NAME = Representation.class.getName();
private static final Logger LOGGER = LoggerFactory.getLogger(RepresentationAuthorizationResource.class);
/**
* Removes permissions for selected user to selected representation version.<br/><br/>
* Permissions option:<br/>
* <li>all</li>
* <li>read</li>
* <li>write</li>
* <li>delete</li>
* <li>administration</li>
*
* @param globalId cloud id of the record (required).
* @param schema schema of representation (required).
* @param version a specific version of the representation(required).
* @param userName username as part of credential (required).
* @param permission permission as part of credential (required).
* @return response tells you if authorization has been updated or not
* @summary Permissions removal
*/
@DELETE
@Path("/permissions/{" + P_PERMISSION + "}/users/{" + P_USER_NAME + "}")
@PreAuthorize("hasPermission(#globalId.concat('/').concat(#schema).concat('/').concat(#version),"
+ " 'eu.europeana.cloud.common.model.Representation', write)")
public Response removePermissions(@PathParam(P_CLOUDID) String globalId,
@PathParam(P_REPRESENTATIONNAME) String schema,
@PathParam(P_VER) String version,
@PathParam(P_USER_NAME) String userName,
@PathParam(P_PERMISSION) String permission) {
ParamUtil.require(P_CLOUDID, globalId);
ParamUtil.require(P_REPRESENTATIONNAME, schema);
ParamUtil.require(P_VER, version);
ParamUtil.require(P_USER_NAME, userName);
ParamUtil.require(P_PERMISSION, permission);
ParamUtil.validate(P_PERMISSION, permission, acceptedPermissionValues);
eu.europeana.cloud.common.model.Permission _permission = eu.europeana.cloud.common.model.Permission.valueOf(permission.toUpperCase());
ObjectIdentity versionIdentity = new ObjectIdentityImpl(REPRESENTATION_CLASS_NAME,
globalId + "/" + schema + "/" + version);
LOGGER.info("Removing privileges for user '{}' to '{}' with key '{}'", userName, versionIdentity.getType(), versionIdentity.getIdentifier());
List<Permission> permissionsToBeRemoved = Arrays.asList(_permission.getSpringPermissions());
permissionsGrantingManager.removePermissions(versionIdentity, userName, permissionsToBeRemoved);
return Response.noContent().build();
}
/**
* Modify authorization of versions operation. Updates authorization for a
* specific representation version.
* <p/>
* <strong>Write permissions required.</strong>
*
* @param globalId cloud id of the record (required).
* @param schema schema of representation (required).
* @param version a specific version of the representation(required).
* @param username username as part of credential (required).
* @param permission permission as part of credential (required).
* @return response tells you if authorization has been updated or not
* @summary update authorization for a representation version
* @statuscode 200 object has been updated.
* @statuscode 204 object has not been updated.
*/
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("/permissions/{" + P_PERMISSION + "}/users/{" + P_USER_NAME + "}")
@PreAuthorize("hasPermission(#globalId.concat('/').concat(#schema).concat('/').concat(#version),"
+ " 'eu.europeana.cloud.common.model.Representation', write)")
public Response updateAuthorization(
@PathParam(P_CLOUDID) String globalId,
@PathParam(P_REPRESENTATIONNAME) String schema,
@PathParam(P_VER) String version,
@PathParam(P_USER_NAME) String username,
@PathParam(P_PERMISSION) String permission
) {
ParamUtil.require(P_CLOUDID, globalId);
ParamUtil.require(P_REPRESENTATIONNAME, schema);
ParamUtil.require(P_VER, version);
ParamUtil.require(P_USER_NAME, username);
ParamUtil.require(P_PERMISSION, permission);
ParamUtil.validate(P_PERMISSION, permission, acceptedPermissionValues);
ObjectIdentity versionIdentity = new ObjectIdentityImpl(REPRESENTATION_CLASS_NAME,
globalId + "/" + schema + "/" + version);
eu.europeana.cloud.common.model.Permission _permission = eu.europeana.cloud.common.model.Permission.valueOf(permission.toUpperCase());
MutableAcl versionAcl = (MutableAcl) mutableAclService.readAclById(versionIdentity);
if (versionAcl != null) {
try {
final Permission[] permissions = _permission.getSpringPermissions();
for (Permission singlePermission : permissions) {
versionAcl.insertAce(versionAcl.getEntries().size(), singlePermission, new PrincipalSid(username), true);
}
mutableAclService.updateAcl(versionAcl);
} catch (Exception e) {
LOGGER.error(e.getMessage());
return Response.notModified("Authorization has NOT been updated!").build();
}
return Response.ok("Authorization has been updated!").build();
} else {
return Response.notModified("Authorization has NOT been updated!").build();
}
}
/**
* Gives read access to everyone (even anonymous users) for the specified File.
* <p/>
* <strong>Write permissions required.</strong>
*
* @param globalId cloud id of the record (required).
* @param schema schema of representation (required).
* @param version a specific version of the representation(required).
* @return response tells you if authorization has been updated or not
* @statuscode 204 object has been updated.
*/
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@PreAuthorize("hasPermission(#globalId.concat('/').concat(#schema).concat('/').concat(#version),"
+ " 'eu.europeana.cloud.common.model.Representation', write)")
@Path("/permit")
public Response giveReadAccessToEveryone(
@PathParam(P_CLOUDID) String globalId,
@PathParam(P_REPRESENTATIONNAME) String schema,
@PathParam(P_VER) String version) {
ObjectIdentity versionIdentity = new ObjectIdentityImpl(REPRESENTATION_CLASS_NAME,
globalId + "/" + schema + "/" + version);
MutableAcl versionAcl = (MutableAcl) mutableAclService.readAclById(versionIdentity);
Sid anonRole = new GrantedAuthoritySid("ROLE_ANONYMOUS");
Sid userRole = new GrantedAuthoritySid("ROLE_USER");
if (versionAcl != null) {
versionAcl.insertAce(versionAcl.getEntries().size(), BasePermission.READ, anonRole, true);
versionAcl.insertAce(versionAcl.getEntries().size(), BasePermission.READ, userRole, true);
mutableAclService.updateAcl(versionAcl);
return Response.ok("Authorization has been updated!").build();
} else {
return Response.notModified("Authorization has NOT been updated!").build();
}
}
}