From 58a6568efcf85cd948f940473e9d4384215c5f93 Mon Sep 17 00:00:00 2001 From: John Woodlock Date: Sun, 26 Aug 2012 16:57:58 +1000 Subject: [PATCH] add report permission checking --- .../platform/api/ReportsApiResource.java | 122 +++++++++++++----- .../mifosng/platform/user/domain/AppUser.java | 13 ++ .../mifosng/platform/user/domain/Role.java | 5 + 3 files changed, 106 insertions(+), 34 deletions(-) diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/ReportsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/ReportsApiResource.java index 7a03f1a63..d458b08f2 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/ReportsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/ReportsApiResource.java @@ -20,6 +20,9 @@ import org.mifosng.platform.ReadExtraDataAndReportingService; import org.mifosng.platform.api.data.GenericResultsetData; import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService; import org.mifosng.platform.api.infrastructure.ApiParameterHelper; +import org.mifosng.platform.exceptions.NoAuthorizationException; +import org.mifosng.platform.security.PlatformSecurityContext; +import org.mifosng.platform.user.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -29,31 +32,43 @@ import org.springframework.stereotype.Component; @Scope("singleton") public class ReportsApiResource { + private final PlatformSecurityContext context; + + @Autowired + public ReportsApiResource(final PlatformSecurityContext context) { + this.context = context; + } + @Autowired private ReadExtraDataAndReportingService readExtraDataAndReportingService; @Autowired private ApiJsonSerializerService apiJsonSerializerService; - + @GET - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON, "application/x-msdownload" }) + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, "application/x-msdownload" }) public Response retrieveReportList(@Context final UriInfo uriInfo) { Map extractedQueryParams = new HashMap(); - - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - boolean exportCsv = ApiParameterHelper.exportCsv(uriInfo.getQueryParameters()); + + boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo + .getQueryParameters()); + boolean exportCsv = ApiParameterHelper.exportCsv(uriInfo + .getQueryParameters()); if (!exportCsv) { - GenericResultsetData result = this.readExtraDataAndReportingService.retrieveGenericResultset(".", ".", extractedQueryParams); - - final String json = this.apiJsonSerializerService.serializeGenericResultsetDataToJson(prettyPrint, result); - + GenericResultsetData result = this.readExtraDataAndReportingService + .retrieveGenericResultset(".", ".", extractedQueryParams); + + final String json = this.apiJsonSerializerService + .serializeGenericResultsetDataToJson(prettyPrint, result); + return Response.ok().entity(json).build(); } - StreamingOutput result = this.readExtraDataAndReportingService.retrieveReportCSV(".", ".", extractedQueryParams); + StreamingOutput result = this.readExtraDataAndReportingService + .retrieveReportCSV(".", ".", extractedQueryParams); return Response .ok() @@ -64,44 +79,62 @@ public class ReportsApiResource { @GET @Path("{reportName}") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON, "application/x-msdownload","application/vnd.ms-excel", "application/pdf", "text/html" }) + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, "application/x-msdownload", + "application/vnd.ms-excel", "application/pdf", "text/html" }) public Response retrieveReport( @PathParam("reportName") final String reportName, @Context final UriInfo uriInfo) { - MultivaluedMap queryParams = uriInfo.getQueryParameters(); - - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - boolean exportCsv = ApiParameterHelper.exportCsv(uriInfo.getQueryParameters()); - boolean parameterType = ApiParameterHelper.parameterType(uriInfo.getQueryParameters()); + MultivaluedMap queryParams = uriInfo + .getQueryParameters(); + + boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo + .getQueryParameters()); + boolean exportCsv = ApiParameterHelper.exportCsv(uriInfo + .getQueryParameters()); + boolean parameterType = ApiParameterHelper.parameterType(uriInfo + .getQueryParameters()); + + checkUserPermissionForReport(reportName, parameterType); String parameterTypeValue = null; if (!parameterType) { parameterTypeValue = "report"; - if (this.readExtraDataAndReportingService.getReportType(reportName).equalsIgnoreCase("Pentaho")) { - Map reportParams = getReportParams(queryParams, true); - return this.readExtraDataAndReportingService.processPentahoRequest(reportName, queryParams.getFirst("output-type"), reportParams); + if (this.readExtraDataAndReportingService.getReportType(reportName) + .equalsIgnoreCase("Pentaho")) { + Map reportParams = getReportParams(queryParams, + true); + return this.readExtraDataAndReportingService + .processPentahoRequest(reportName, + queryParams.getFirst("output-type"), + reportParams); } } else { parameterTypeValue = "parameter"; } if (!exportCsv) { - - Map reportParams = getReportParams(queryParams, false); - - GenericResultsetData result = this.readExtraDataAndReportingService.retrieveGenericResultset(reportName, parameterTypeValue, reportParams); - final String json = this.apiJsonSerializerService.serializeGenericResultsetDataToJson(prettyPrint, result); - - return Response.ok().entity(json).type(MediaType.APPLICATION_JSON).build(); + Map reportParams = getReportParams(queryParams, + false); + + GenericResultsetData result = this.readExtraDataAndReportingService + .retrieveGenericResultset(reportName, parameterTypeValue, + reportParams); + + final String json = this.apiJsonSerializerService + .serializeGenericResultsetDataToJson(prettyPrint, result); + + return Response.ok().entity(json).type(MediaType.APPLICATION_JSON) + .build(); } // CSV Export Map reportParams = getReportParams(queryParams, false); - StreamingOutput result = this.readExtraDataAndReportingService.retrieveReportCSV(reportName, parameterTypeValue, reportParams); - + StreamingOutput result = this.readExtraDataAndReportingService + .retrieveReportCSV(reportName, parameterTypeValue, reportParams); + return Response .ok() .entity(result) @@ -111,7 +144,26 @@ public class ReportsApiResource { + ".csv").build(); } - private Map getReportParams(final MultivaluedMap queryParams, final Boolean isPentaho) { + private void checkUserPermissionForReport(String reportName, + boolean parameterType) { + + // Anyone can run a 'report' that is simply getting possible parameter + // (dropdown listbox) values. + + if (!parameterType) { + AppUser currentUser = context.authenticatedUser(); + if (currentUser.hasNotPermissionForReport(reportName)) { + // TODO - message isnt passing back the message in the string in + // the json just a generalised not authorised message + throw new NoAuthorizationException( + "Not Authorised to Run Report: " + reportName); + } + } + } + + private Map getReportParams( + final MultivaluedMap queryParams, + final Boolean isPentaho) { Map reportParams = new HashMap(); Set keys = queryParams.keySet(); @@ -120,9 +172,11 @@ public class ReportsApiResource { for (String k : keys) { if (k.startsWith("R_")) { - if (isPentaho) pKey = k.substring(2); - else pKey = "${" + k.substring(2) + "}"; - + if (isPentaho) + pKey = k.substring(2); + else + pKey = "${" + k.substring(2) + "}"; + pValue = queryParams.get(k).get(0); reportParams.put(pKey, pValue); } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/AppUser.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/AppUser.java index f0c0b0969..c1b522387 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/AppUser.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/AppUser.java @@ -244,6 +244,18 @@ public class AppUser extends AbstractAuditableCustom implements P public boolean canNotMakeRepaymentOnLoanInPast() { return hasNotPermissionForAnyOf("CAN_MAKE_LOAN_REPAYMENT_IN_THE_PAST_ROLE", "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE"); } + public boolean hasNotPermissionForReport(String reportName) { + + for (Role role : this.roles) { + if ((role.getName().equalsIgnoreCase("Super User")) || (role.getName().equalsIgnoreCase("Read Only"))) { + return false; + } + } + + if (hasPermissionTo("CAN_RUN_" + reportName)) return false; + + return true; + } public boolean hasNotPermissionForAnyOf(final String... permissionCodes) { boolean hasNotPermission = true; @@ -268,6 +280,7 @@ public class AppUser extends AbstractAuditableCustom implements P return match; } + public boolean hasIdOf(final Long userId) { return getId().equals(userId); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Role.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Role.java index 20f07b747..b7ca99142 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Role.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Role.java @@ -85,4 +85,9 @@ public class Role extends AbstractAuditableCustom { this.permissions = new HashSet(selectedPermissions); } } + + public String getName() { + return name; + } + } \ No newline at end of file