diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/AdditionalFieldsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/AdditionalFieldsApiResource.java index 5ee1a81ee..9d1813627 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/AdditionalFieldsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/AdditionalFieldsApiResource.java @@ -30,7 +30,10 @@ import org.mifosng.platform.api.data.EntityIdentifier; 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.exceptions.PlatformApiDataValidationException; +import org.mifosng.platform.security.PlatformSecurityContext; +import org.mifosng.platform.user.domain.AppUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -42,38 +45,55 @@ import org.springframework.stereotype.Component; @Scope("singleton") public class AdditionalFieldsApiResource { - private final static Logger logger = LoggerFactory.getLogger(AdditionalFieldsApiResource.class); + private final static Logger logger = LoggerFactory + .getLogger(AdditionalFieldsApiResource.class); + + private final PlatformSecurityContext context; + + @Autowired + public AdditionalFieldsApiResource(final PlatformSecurityContext context) { + this.context = context; + } @Autowired private ReadExtraDataAndReportingService readExtraDataAndReportingService; - + @Autowired private ApiJsonSerializerService apiJsonSerializerService; @GET - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String datasets(@QueryParam("type") final String type, @Context final UriInfo uriInfo) { + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String datasets(@QueryParam("type") final String type, + @Context final UriInfo uriInfo) { - List result = this.readExtraDataAndReportingService.retrieveExtraDatasetNames(type); + List result = this.readExtraDataAndReportingService + .retrieveExtraDatasetNames(type); - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - return this.apiJsonSerializerService.serializeAdditionalFieldsSetDataToJson(prettyPrint, result); + boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo + .getQueryParameters()); + return this.apiJsonSerializerService + .serializeAdditionalFieldsSetDataToJson(prettyPrint, result); } @GET @Path("{type}/{set}/{id}") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) public String extraData(@PathParam("type") final String type, @PathParam("set") final String set, @PathParam("id") final Long id, @Context final UriInfo uriInfo) { - try { - GenericResultsetData result = this.readExtraDataAndReportingService.retrieveExtraData(type, set, id); + checkUserPermissionForSet(type, set, "READ"); - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - return this.apiJsonSerializerService.serializeGenericResultsetDataToJson(prettyPrint, result); + try { + GenericResultsetData result = this.readExtraDataAndReportingService + .retrieveExtraData(type, set, id); + + boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo + .getQueryParameters()); + return this.apiJsonSerializerService + .serializeGenericResultsetDataToJson(prettyPrint, result); } catch (InvalidSqlException e) { List dataValidationErrors = new ArrayList(); ApiParameterError error = ApiParameterError.parameterError( @@ -88,12 +108,14 @@ public class AdditionalFieldsApiResource { @POST @Path("{type}/{set}/{id}") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) public Response saveExtraData(@PathParam("type") final String type, @PathParam("set") final String set, @PathParam("id") final Long id, final String jsonRequestBody) { + checkUserPermissionForSet(type, set, "UPDATE"); + try { Map queryParams = new HashMap(); @@ -139,4 +161,14 @@ public class AdditionalFieldsApiResource { "Validation errors exist.", dataValidationErrors); } } + + private void checkUserPermissionForSet(String type, String set, + String accessType) { + AppUser currentUser = context.authenticatedUser(); + if (currentUser.hasNotPermissionForSet(type, set, accessType)) { + throw new NoAuthorizationException("Not Authorised to Use Set: " + + set + " of Type: " + type); + } + } + } \ No newline at end of file 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 c1b522387..0cfa1fc93 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 @@ -25,102 +25,109 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; @Entity -@Table(name = "m_appuser", uniqueConstraints=@UniqueConstraint(columnNames = {"username"}, name="username_org")) -public class AppUser extends AbstractAuditableCustom implements PlatformUser { +@Table(name = "m_appuser", uniqueConstraints = @UniqueConstraint(columnNames = { "username" }, name = "username_org")) +public class AppUser extends AbstractAuditableCustom implements + PlatformUser { - @Column(name = "email", nullable=false, length=100) - private String email; + @Column(name = "email", nullable = false, length = 100) + private String email; - @Column(name = "username", nullable=false, length=100) - private String username; - - @Column(name = "firstname", nullable=false, length=100) - private String firstname; - - @Column(name = "lastname", nullable=false, length=100) - private String lastname; + @Column(name = "username", nullable = false, length = 100) + private String username; - @Column(name = "password", nullable=false) - private String password; + @Column(name = "firstname", nullable = false, length = 100) + private String firstname; - @Column(name = "nonexpired", nullable=false) - private boolean accountNonExpired; + @Column(name = "lastname", nullable = false, length = 100) + private String lastname; - @Column(name = "nonlocked", nullable=false) - private final boolean accountNonLocked; + @Column(name = "password", nullable = false) + private String password; - @Column(name = "nonexpired_credentials", nullable=false) - private final boolean credentialsNonExpired; + @Column(name = "nonexpired", nullable = false) + private boolean accountNonExpired; - @Column(name = "enabled", nullable=false) - private boolean enabled; + @Column(name = "nonlocked", nullable = false) + private final boolean accountNonLocked; - @SuppressWarnings("unused") - @Column(name = "firsttime_login_remaining", nullable=false) - private boolean firstTimeLoginRemaining; - - @Column(name = "is_deleted", nullable=false) - private boolean deleted; + @Column(name = "nonexpired_credentials", nullable = false) + private final boolean credentialsNonExpired; - @ManyToOne - @JoinColumn(name = "office_id") - private Office office; + @Column(name = "enabled", nullable = false) + private boolean enabled; - @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "m_appuser_role", joinColumns = @JoinColumn(name = "appuser_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) - private Set roles; + @SuppressWarnings("unused") + @Column(name = "firsttime_login_remaining", nullable = false) + private boolean firstTimeLoginRemaining; + + @Column(name = "is_deleted", nullable = false) + private boolean deleted; + + @ManyToOne + @JoinColumn(name = "office_id") + private Office office; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "m_appuser_role", joinColumns = @JoinColumn(name = "appuser_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) + private Set roles; public static AppUser createNew(final Office office, - final Set allRoles, final String username, final String email, - final String firstname, final String lastname, final String password) { - + final Set allRoles, final String username, + final String email, final String firstname, final String lastname, + final String password) { + boolean userEnabled = true; boolean userAccountNonExpired = true; boolean userCredentialsNonExpired = true; boolean userAccountNonLocked = true; - + Collection authorities = new ArrayList(); - authorities.add(new SimpleGrantedAuthority("DUMMY_ROLE_NOT_USED_OR_PERSISTED_TO_AVOID_EXCEPTION")); - - User user = new User(username, password, userEnabled, userAccountNonExpired, userCredentialsNonExpired, userAccountNonLocked, authorities); + authorities.add(new SimpleGrantedAuthority( + "DUMMY_ROLE_NOT_USED_OR_PERSISTED_TO_AVOID_EXCEPTION")); + + User user = new User(username, password, userEnabled, + userAccountNonExpired, userCredentialsNonExpired, + userAccountNonLocked, authorities); return new AppUser(office, user, allRoles, email, firstname, lastname); } - protected AppUser() { - this.office = null; - this.email = null; - this.username = null; - this.password = null; - this.accountNonExpired = false; - this.accountNonLocked = false; - this.credentialsNonExpired = false; - this.enabled = false; - this.roles = new HashSet(); - this.firstTimeLoginRemaining = true; - } - - public AppUser(final Office office, final User user, final Set roles, final String email, final String firstname, final String lastname) { - this.office = office; - this.email = email.trim(); - this.username = user.getUsername().trim(); - this.firstname = firstname.trim(); - this.lastname = lastname.trim(); - this.password = user.getPassword().trim(); - this.accountNonExpired = user.isAccountNonExpired(); - this.accountNonLocked = user.isAccountNonLocked(); - this.credentialsNonExpired = user.isCredentialsNonExpired(); - this.enabled = user.isEnabled(); - this.roles = roles; + protected AppUser() { + this.office = null; + this.email = null; + this.username = null; + this.password = null; + this.accountNonExpired = false; + this.accountNonLocked = false; + this.credentialsNonExpired = false; + this.enabled = false; + this.roles = new HashSet(); this.firstTimeLoginRemaining = true; - } + } + + public AppUser(final Office office, final User user, final Set roles, + final String email, final String firstname, final String lastname) { + this.office = office; + this.email = email.trim(); + this.username = user.getUsername().trim(); + this.firstname = firstname.trim(); + this.lastname = lastname.trim(); + this.password = user.getPassword().trim(); + this.accountNonExpired = user.isAccountNonExpired(); + this.accountNonLocked = user.isAccountNonLocked(); + this.credentialsNonExpired = user.isCredentialsNonExpired(); + this.enabled = user.isEnabled(); + this.roles = roles; + this.firstTimeLoginRemaining = true; + } public void updatePassword(final String encodePassword) { this.password = encodePassword; this.firstTimeLoginRemaining = false; } - - public void update(final Set allRoles, final Office office, final UserCommand userCommand) { - + + public void update(final Set allRoles, final Office office, + final UserCommand userCommand) { + if (userCommand.isRolesChanged() && !allRoles.isEmpty()) { this.roles.clear(); this.roles = allRoles; @@ -141,9 +148,10 @@ public class AppUser extends AbstractAuditableCustom implements P this.email = userCommand.getEmail(); } } - + /** - * Delete is a soft delete. Updates flag so it wont appear in query/report results. + * Delete is a soft delete. Updates flag so it wont appear in + * query/report results. * * Any fields with unique constraints and prepended with id of record. */ @@ -159,53 +167,54 @@ public class AppUser extends AbstractAuditableCustom implements P return deleted; } - @Override - public Collection getAuthorities() { - return this.populateGrantedAuthorities(); - } + @Override + public Collection getAuthorities() { + return this.populateGrantedAuthorities(); + } - private List populateGrantedAuthorities() { - List grantedAuthorities = new ArrayList(); - for (Role role :this.roles) { - Collection permissions = role.getPermissions(); - for (Permission permission : permissions) { - grantedAuthorities.add(new SimpleGrantedAuthority(permission.code())); - } - } - return grantedAuthorities; - } + private List populateGrantedAuthorities() { + List grantedAuthorities = new ArrayList(); + for (Role role : this.roles) { + Collection permissions = role.getPermissions(); + for (Permission permission : permissions) { + grantedAuthorities.add(new SimpleGrantedAuthority(permission + .code())); + } + } + return grantedAuthorities; + } - @Override - public String getPassword() { - return this.password; - } + @Override + public String getPassword() { + return this.password; + } - @Override - public String getUsername() { - return this.username; - } + @Override + public String getUsername() { + return this.username; + } - @Override - public boolean isAccountNonExpired() { - return this.accountNonExpired; - } + @Override + public boolean isAccountNonExpired() { + return this.accountNonExpired; + } - @Override - public boolean isAccountNonLocked() { - return this.accountNonLocked; - } + @Override + public boolean isAccountNonLocked() { + return this.accountNonLocked; + } - @Override - public boolean isCredentialsNonExpired() { - return this.credentialsNonExpired; - } + @Override + public boolean isCredentialsNonExpired() { + return this.credentialsNonExpired; + } - @Override - public boolean isEnabled() { - return this.enabled; - } - - public String getFirstname() { + @Override + public boolean isEnabled() { + return this.enabled; + } + + public String getFirstname() { return firstname; } @@ -213,50 +222,82 @@ public class AppUser extends AbstractAuditableCustom implements P return lastname; } - public String getEmail() { - return this.email; - } + public String getEmail() { + return this.email; + } - public Set getRoles() { - return this.roles; - } + public Set getRoles() { + return this.roles; + } - public Office getOffice() { - return this.office; - } + public Office getOffice() { + return this.office; + } public boolean canNotApproveLoanInPast() { - return hasNotPermissionForAnyOf("CAN_APPROVE_LOAN_IN_THE_PAST_ROLE", "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE"); + return hasNotPermissionForAnyOf("CAN_APPROVE_LOAN_IN_THE_PAST_ROLE", + "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE"); } public boolean canNotRejectLoanInPast() { - return hasNotPermissionForAnyOf("CAN_REJECT_LOAN_IN_THE_PAST_ROLE", "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE"); + return hasNotPermissionForAnyOf("CAN_REJECT_LOAN_IN_THE_PAST_ROLE", + "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE"); } public boolean canNotWithdrawByClientLoanInPast() { - return hasNotPermissionForAnyOf("CAN_WITHDRAW_LOAN_IN_THE_PAST_ROLE", "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE"); + return hasNotPermissionForAnyOf("CAN_WITHDRAW_LOAN_IN_THE_PAST_ROLE", + "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE"); } public boolean canNotDisburseLoanInPast() { - return hasNotPermissionForAnyOf("CAN_DISBURSE_LOAN_IN_THE_PAST_ROLE", "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE"); + return hasNotPermissionForAnyOf("CAN_DISBURSE_LOAN_IN_THE_PAST_ROLE", + "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE"); } public boolean canNotMakeRepaymentOnLoanInPast() { - return hasNotPermissionForAnyOf("CAN_MAKE_LOAN_REPAYMENT_IN_THE_PAST_ROLE", "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE"); + 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"))) { + if (role.getName().equalsIgnoreCase("Super User")) + return false; + if (role.getName().equalsIgnoreCase("Read Only")) return false; - } } - - if (hasPermissionTo("CAN_RUN_" + reportName)) return false; - + + if (hasPermissionTo("CAN_RUN_" + reportName)) + return false; + return true; } - + + public boolean hasNotPermissionForSet(String type, String set, + String accessType) { + + for (Role role : this.roles) { + + if (role.getName().equalsIgnoreCase("Super User")) + return false; + + if (accessType.equalsIgnoreCase("READ")) { + + if (role.getName().equalsIgnoreCase("Read Only")) + return false; + + } + } + + String matchPermission = "CAN_" + accessType + "_" + type + "_x" + set; + if (hasPermissionTo(matchPermission)) + return false; + + return true; + } + public boolean hasNotPermissionForAnyOf(final String... permissionCodes) { boolean hasNotPermission = true; for (String permissionCode : permissionCodes) { @@ -280,7 +321,6 @@ public class AppUser extends AbstractAuditableCustom implements P return match; } - public boolean hasIdOf(final Long userId) { return getId().equals(userId);