private AuthZ() {
setupProvider();
}
+
+ //
+ // URI paths that require special handling
+ //
+ public static final String REPORTS_MIME_OUTPUTS = "reports/mimetypes";
+ public static final String ACCOUNT_PERMISSIONS = "accounts/*/accountperms";
+ public static final String STRUCTURED_DATE_REQUEST = "structureddate";
+ public static final String PASSWORD_RESET = "accounts/requestpasswordreset";
+ public static final String PROCESS_PASSWORD_RESET = "accounts/processpasswordreset";
+ public static final String REPORTS_INVOKE = "reports/*/invoke";
+ public static final String BATCH_INVOKE = "batch/*/invoke";
/**
*
</tenant:serviceBindings>
<!-- end blob service meta-data -->
+ <!-- begin batch-invoke service meta-data -->
+ <tenant:serviceBindings id="batch/invoke" merge:matcher="id" name="batch/invoke"
+ type="utility" version="1.0">
+ <!-- other URI paths through which this service could be accessed -->
+ <!-- <service:uriPath xmlns:service='http://collectionspace.org/services/config/service'> /batch/*/invoke </service:uriPath> -->
+ <service:documentHandler xmlns:service="http://collectionspace.org/services/config/service">org.collectionspace.services.batch.nuxeo.BatchDocumentModelHandler
+ </service:documentHandler>
+ <!-- <service:validatorHandler xmlns:service='http://collectionspace.org/services/config/service'> org.collectionspace.services.batch.nuxeo.BatchDocumentModelHandler
+ </service:validatorHandler> -->
+ <service:object xmlns:service="http://collectionspace.org/services/config/service" name="BatchInvoke"
+ version="1.0">
+ <service:part id="0" control_group="Managed" versionable="true" auditable="false" label="batchinvoke_system"
+ updated="" order="0">
+ <service:content contentType="application/xml">
+ <service:xmlContent namespaceURI="http://collectionspace.org/services/config/system"
+ schemaLocation="http://collectionspace.org/services/config/system http://collectionspace.org/services/config/system/system-response.xsd" />
+ </service:content>
+ </service:part>
+ </service:object>
+ </tenant:serviceBindings>
+ <!-- end batch-invoke service meta-data -->
+
<!-- begin batch service meta-data -->
<tenant:serviceBindings id="Batch" merge:matcher="id" name="Batch" type="utility" version="1.0">
<service:repositoryDomain xmlns:service="http://collectionspace.org/services/config/service">default-domain</service:repositoryDomain>
</tenant:serviceBindings>
<!-- end Index service meta-data -->
+ <!-- begin reports-invoke service meta-data -->
+ <tenant:serviceBindings id="reports/invoke" merge:matcher="id" name="reports/invoke"
+ type="utility" version="1.0">
+ <!-- other URI paths through which this service could be accessed -->
+ <!-- <service:uriPath xmlns:service='http://collectionspace.org/services/config/service'> /reports/*/invoke </service:uriPath> -->
+ <service:documentHandler xmlns:service="http://collectionspace.org/services/config/service">org.collectionspace.services.report.nuxeo.ReportDocumentModelHandler
+ </service:documentHandler>
+ <!-- <service:validatorHandler xmlns:service='http://collectionspace.org/services/config/service'> org.collectionspace.services.report.nuxeo.ReportDocumentModelHandler
+ </service:validatorHandler> -->
+ <service:object xmlns:service="http://collectionspace.org/services/config/service" name="ReportsInvoke"
+ version="1.0">
+ <service:part id="0" control_group="Managed" versionable="true" auditable="false" label="reportsinvoke_system"
+ updated="" order="0">
+ <service:content contentType="application/xml">
+ <service:xmlContent namespaceURI="http://collectionspace.org/services/config/system"
+ schemaLocation="http://collectionspace.org/services/config/system http://collectionspace.org/services/config/system/system-response.xsd" />
+ </service:content>
+ </service:part>
+ </service:object>
+ </tenant:serviceBindings>
+ <!-- end reports-invoke service meta-data -->
+
<!-- begin report service meta-data -->
<tenant:serviceBindings id="Reports" merge:matcher="id" name="Reports" type="utility" version="1.0">
<!-- other URI paths through which this service could be accessed -->
/** The Constant logger. */
private static final Logger logger = LoggerFactory.getLogger(SecurityInterceptor.class);
- private static final String REPORTS_MIME_OUTPUTS = "reports/mimetypes";
- private static final String ACCOUNT_PERMISSIONS = "accounts/*/accountperms";
- private static final String STRUCTURED_DATE_REQUEST = "structureddate";
- private static final String PASSWORD_RESET = "accounts/requestpasswordreset";
- private static final String PROCESS_PASSWORD_RESET = "accounts/processpasswordreset";
+
private static final String SYSTEM_INFO = SystemInfoClient.SERVICE_NAME;
private static final String NUXEO_ADMIN = null;
//
String resName = SecurityUtils.getResourceName(request.getUri()).toLowerCase();
switch (resName) {
- case PASSWORD_RESET:
- case PROCESS_PASSWORD_RESET:
+ case AuthZ.PASSWORD_RESET:
+ case AuthZ.PROCESS_PASSWORD_RESET:
case SYSTEM_INFO:
return true;
}
// STRUCTURED_DATE_REQUEST: All user can request the parsing of a structured date string.
//
switch (resName) {
- case STRUCTURED_DATE_REQUEST:
- case ACCOUNT_PERMISSIONS:
- case REPORTS_MIME_OUTPUTS:
+ case AuthZ.STRUCTURED_DATE_REQUEST:
+ case AuthZ.ACCOUNT_PERMISSIONS:
+ case AuthZ.REPORTS_MIME_OUTPUTS:
result = false;
break;
default:
String resEntity = SecurityUtils.getResourceEntity(resName);
//
- // If the resource entity is acting as a proxy then all sub-resource will map to the resource itself.
- // This essentially means that the sub-resource inherit all the authz permissions of the entity.
+ // If the resource entity is acting as a proxy then all sub-resources will map to the resource itself.
+ // This essentially means sub-resources inherit all the authz permissions of the entity.
//
- if (SecurityUtils.isEntityProxy() == true && !resName.equalsIgnoreCase(ACCOUNT_PERMISSIONS)) {
+ if (SecurityUtils.isResourceProxied(resName) == true) {
resName = resEntity;
+ } else {
+ //
+ // If our resName is not proxied, we may need to tweak it.
+ //
+ switch (resName) {
+ case AuthZ.REPORTS_INVOKE:
+ case AuthZ.BATCH_INVOKE: {
+ resName = resName.replace("/*/", "/");
+ }
+ }
}
//
- // Make sure the account is current and active
+ // Make sure the account of the user making the request is current and active
//
checkActive();
public class SecurityUtils {
private static final Logger logger = LoggerFactory.getLogger(SecurityUtils.class);
+
public static final String URI_PATH_SEPARATOR = "/";
public static final int MIN_PASSWORD_LENGTH = 8;
public static final int MAX_PASSWORD_LENGTH = 24;
uriPath = uriPath.replace("//", "/"); // replace duplicate '/' characters
uriPath = uriPath.startsWith("/") ? uriPath.substring(1) : uriPath; // if present, strip the leading '/' character
+
return uriPath;
}
*
* @return true, if is entity proxy is acting as a proxy for all sub-resources
*/
- public static final boolean isEntityProxy() {
- //
- // should be getting this information from the cspace config settings (tenent bindings file).
- return true;
+ public static final boolean isResourceProxied(String resName) {
+ boolean result = true;
+
+ switch (resName) {
+ case AuthZ.REPORTS_INVOKE:
+ case AuthZ.BATCH_INVOKE:
+ case AuthZ.ACCOUNT_PERMISSIONS:
+ result = false;
+ break;
+ }
+
+ return result;
}
import org.collectionspace.services.jaxb.AbstractCommonList;
import org.collectionspace.services.report.nuxeo.ReportDocumentModelHandler;
import org.collectionspace.services.publicitem.PublicitemsCommon;
+import org.collectionspace.services.authorization.AuthZ;
+import org.collectionspace.services.authorization.CSpaceResource;
+import org.collectionspace.services.authorization.URIResourceImpl;
+import org.collectionspace.services.authorization.perms.ActionType;
import org.collectionspace.services.client.IQueryManager;
import org.collectionspace.services.client.PayloadPart;
import org.collectionspace.services.client.PoxPayloadIn;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.Response.Status;
@Path(ReportClient.SERVICE_PATH)
@Consumes("application/xml")
private static String REPORTS_STD_GROUPCSID_PARAM = "groupcsid";
private static String REPORTS_STD_CSIDLIST_PARAM = "csidlist";
private static String REPORTS_STD_TENANTID_PARAM = "tenantid";
+ private static String REPORT_INVOKE_RESNAME = "reports/invoke";
@Override
protected String getVersionString() {
StringBuffer outMimeType = new StringBuffer();
StringBuffer outReportFileName = new StringBuffer();
ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
- InputStream reportInputStream = invokeReport(ctx, csid, invContext, outMimeType, outReportFileName);
- response = PublicItemUtil.publishToRepository(
- (PublicitemsCommon)null,
- resourceMap,
- uriInfo,
- getRepositoryClient(ctx),
- ctx,
- reportInputStream,
- outReportFileName.toString());
+
+ if (isAuthorizedToInvokeReports(ctx) == true) {
+ InputStream reportInputStream = invokeReport(ctx, csid, invContext, outMimeType, outReportFileName);
+ response = PublicItemUtil.publishToRepository(
+ (PublicitemsCommon)null,
+ resourceMap,
+ uriInfo,
+ getRepositoryClient(ctx),
+ ctx,
+ reportInputStream,
+ outReportFileName.toString());
+ } else {
+ ResponseBuilder builder = Response.status(Status.FORBIDDEN);
+ response = builder.build();
+ }
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.POST_FAILED);
}
return response;
}
+
+ /*
+ * This method allows backward compatibility with the old API for running reports.
+ */
+ private boolean isAuthorizedToInvokeReports(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
+ boolean result = true;
+
+ //
+ // Until we enforce a user having POST perms on "/reports/*/invoke", we will continue to allow users with
+ // POST perms on "/reports" to run reports -see JIRA issue https://collectionspace.atlassian.net/browse/DRYD-732
+ //
+ // To start enforcing POST perms on "/reports/*/invoke", uncomment the following block of code
+ //
+
+ /*
+ CSpaceResource res = new URIResourceImpl(ctx.getTenantId(), REPORT_INVOKE_RESNAME, AuthZ.getMethod(ActionType.CREATE));
+ if (AuthZ.get().isAccessAllowed(res) == false) {
+ result = false;
+ }
+ */
+
+ return result;
+ }
+ /**
+ * This method is deprecated at of CollectionSpace v5.3.
+ * @param ui
+ * @param csid
+ * @param invContext
+ * @return
+ */
@POST
@Path("{csid}")
+ @Deprecated
public Response invokeReport(
@Context UriInfo ui,
@PathParam("csid") String csid,
InvocationContext invContext) {
Response response = null;
+ try {
+ StringBuffer outMimeType = new StringBuffer();
+ StringBuffer outFileName = new StringBuffer();
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
+
+ if (isAuthorizedToInvokeReports(ctx) == true) {
+ InputStream reportInputStream = invokeReport(ctx, csid, invContext, outMimeType, outFileName);
+ // Need to set response type for what is requested...
+ ResponseBuilder builder = Response.ok(reportInputStream, outMimeType.toString());
+ builder = builder.header("Content-Disposition","inline;filename=\""+ outFileName.toString() +"\"");
+ response = builder.build();
+ } else {
+ ResponseBuilder builder = Response.status(Status.FORBIDDEN);
+ response = builder.build();
+ }
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ throw bigReThrow(e, ServiceMessages.POST_FAILED + msg != null ? msg : "");
+ }
+
+ return response;
+ }
+
+ @POST
+ @Path("{csid}/invoke")
+ public Response invokeReportNew(
+ @Context UriInfo ui,
+ @PathParam("csid") String csid,
+ InvocationContext invContext) {
+ Response response = null;
+
try {
StringBuffer outMimeType = new StringBuffer();
StringBuffer outFileName = new StringBuffer();