MIFOSX-648: allow user to fetch their own account data no matter what permissions they hold.

This commit is contained in:
Keith Woodlock
2013-09-09 09:54:42 +01:00
parent bdb2162ab7
commit 0de4adf6e5
3 changed files with 472 additions and 512 deletions
@@ -121,7 +121,6 @@ public class SavingsProduct extends AbstractPersistable<Long> {
private Integer withdrawalFeeType; private Integer withdrawalFeeType;
@Column(name = "withdrawal_fee_for_transfer") @Column(name = "withdrawal_fee_for_transfer")
@SuppressWarnings("unused")
private boolean withdrawalFeeApplicableForTransfer; private boolean withdrawalFeeApplicableForTransfer;
@Column(name = "annual_fee_amount", scale = 6, precision = 19, nullable = true) @Column(name = "annual_fee_amount", scale = 6, precision = 19, nullable = true)
@@ -138,7 +137,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType, final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType, final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType, boolean withdrawalFeeApplicableForTransfer, final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType, final boolean withdrawalFeeApplicableForTransfer,
final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay, final AccountingRuleType accountingRuleType) { final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay, final AccountingRuleType accountingRuleType) {
return new SavingsProduct(name, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, return new SavingsProduct(name, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
@@ -484,16 +483,16 @@ public class SavingsProduct extends AbstractPersistable<Long> {
.resource(SAVINGS_PRODUCT_RESOURCE_NAME); .resource(SAVINGS_PRODUCT_RESOURCE_NAME);
if (this.lockinPeriodFrequency == null) { if (this.lockinPeriodFrequency == null) {
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).ignoreIfNull() baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(this.lockinPeriodFrequencyType).ignoreIfNull()
.inMinMaxRange(0, 3); .inMinMaxRange(0, 3);
if (this.lockinPeriodFrequencyType != null) { if (this.lockinPeriodFrequencyType != null) {
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).notNull() baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(this.lockinPeriodFrequency).notNull()
.integerZeroOrGreater(); .integerZeroOrGreater();
} }
} else { } else {
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequencyType).integerZeroOrGreater(); baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(this.lockinPeriodFrequencyType).integerZeroOrGreater();
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).notNull() baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(this.lockinPeriodFrequencyType).notNull()
.inMinMaxRange(0, 3); .inMinMaxRange(0, 3);
} }
@@ -75,25 +75,25 @@ public class UsersApiResource {
@GET @GET
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String retrieveUsers(@Context final UriInfo uriInfo) { public String retrieveAll(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final Collection<AppUserData> users = this.readPlatformService.retrieveAllUsers(); final Collection<AppUserData> users = this.readPlatformService.retrieveAllUsers();
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, users, RESPONSE_DATA_PARAMETERS); return this.toApiJsonSerializer.serialize(settings, users, this.RESPONSE_DATA_PARAMETERS);
} }
@GET @GET
@Path("{userId}") @Path("{userId}")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String retrieveUser(@PathParam("userId") final Long userId, @Context final UriInfo uriInfo) { public String retrieveOne(@PathParam("userId") final Long userId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions, userId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
AppUserData user = this.readPlatformService.retrieveUser(userId); AppUserData user = this.readPlatformService.retrieveUser(userId);
if (settings.isTemplate()) { if (settings.isTemplate()) {
@@ -101,27 +101,27 @@ public class UsersApiResource {
user = AppUserData.template(user, offices); user = AppUserData.template(user, offices);
} }
return this.toApiJsonSerializer.serialize(settings, user, RESPONSE_DATA_PARAMETERS); return this.toApiJsonSerializer.serialize(settings, user, this.RESPONSE_DATA_PARAMETERS);
} }
@GET @GET
@Path("template") @Path("template")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String newUserDetails(@Context final UriInfo uriInfo) { public String template(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final AppUserData user = this.readPlatformService.retrieveNewUserDetails(); final AppUserData user = this.readPlatformService.retrieveNewUserDetails();
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, user, RESPONSE_DATA_PARAMETERS); return this.toApiJsonSerializer.serialize(settings, user, this.RESPONSE_DATA_PARAMETERS);
} }
@POST @POST
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String createUser(final String apiRequestBodyAsJson) { public String create(final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() // final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.createUser() // .createUser() //
@@ -137,7 +137,7 @@ public class UsersApiResource {
@Path("{userId}") @Path("{userId}")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String updateUser(@PathParam("userId") final Long userId, final String apiRequestBodyAsJson) { public String update(@PathParam("userId") final Long userId, final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() // final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.updateUser(userId) // .updateUser(userId) //
@@ -153,7 +153,7 @@ public class UsersApiResource {
@Path("{userId}") @Path("{userId}")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String deleteUser(@PathParam("userId") final Long userId) { public String delete(@PathParam("userId") final Long userId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() // final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.deleteUser(userId) // .deleteUser(userId) //
@@ -89,13 +89,11 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
@JoinTable(name = "m_appuser_role", joinColumns = @JoinColumn(name = "appuser_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) @JoinTable(name = "m_appuser_role", joinColumns = @JoinColumn(name = "appuser_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles; private Set<Role> roles;
public static AppUser fromJson(final Office userOffice, public static AppUser fromJson(final Office userOffice, final Set<Role> allRoles, final JsonCommand command) {
final Set<Role> allRoles, final JsonCommand command) {
final String username = command.stringValueOfParameterNamed("username"); final String username = command.stringValueOfParameterNamed("username");
String password = command.stringValueOfParameterNamed("password"); String password = command.stringValueOfParameterNamed("password");
final Boolean sendPasswordToEmail = command final Boolean sendPasswordToEmail = command.booleanObjectValueOfParameterNamed("sendPasswordToEmail");
.booleanObjectValueOfParameterNamed("sendPasswordToEmail");
if (sendPasswordToEmail.booleanValue()) { if (sendPasswordToEmail.booleanValue()) {
password = new RandomPasswordGenerator(13).generate(); password = new RandomPasswordGenerator(13).generate();
@@ -107,20 +105,16 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
final boolean userAccountNonLocked = true; final boolean userAccountNonLocked = true;
final Collection<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>(); final Collection<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
authorities.add(new SimpleGrantedAuthority( authorities.add(new SimpleGrantedAuthority("DUMMY_ROLE_NOT_USED_OR_PERSISTED_TO_AVOID_EXCEPTION"));
"DUMMY_ROLE_NOT_USED_OR_PERSISTED_TO_AVOID_EXCEPTION"));
final User user = new User(username, password, userEnabled, final User user = new User(username, password, userEnabled, userAccountNonExpired, userCredentialsNonExpired, userAccountNonLocked,
userAccountNonExpired, userCredentialsNonExpired, authorities);
userAccountNonLocked, authorities);
final String email = command.stringValueOfParameterNamed("email"); final String email = command.stringValueOfParameterNamed("email");
final String firstname = command final String firstname = command.stringValueOfParameterNamed("firstname");
.stringValueOfParameterNamed("firstname");
final String lastname = command.stringValueOfParameterNamed("lastname"); final String lastname = command.stringValueOfParameterNamed("lastname");
return new AppUser(userOffice, user, allRoles, email, firstname, return new AppUser(userOffice, user, allRoles, email, firstname, lastname);
lastname);
} }
protected AppUser() { protected AppUser() {
@@ -129,8 +123,8 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
this.roles = new HashSet<Role>(); this.roles = new HashSet<Role>();
} }
public AppUser(final Office office, final User user, final Set<Role> roles, public AppUser(final Office office, final User user, final Set<Role> roles, final String email, final String firstname,
final String email, final String firstname, final String lastname) { final String lastname) {
this.office = office; this.office = office;
this.email = email.trim(); this.email = email.trim();
this.username = user.getUsername().trim(); this.username = user.getUsername().trim();
@@ -169,84 +163,66 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
} }
} }
public Map<String, Object> update(final JsonCommand command, public Map<String, Object> update(final JsonCommand command, final PlatformPasswordEncoder platformPasswordEncoder) {
final PlatformPasswordEncoder platformPasswordEncoder) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>( final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7);
7);
// unencoded password provided // unencoded password provided
final String passwordParamName = "password"; final String passwordParamName = "password";
final String passwordEncodedParamName = "passwordEncoded"; final String passwordEncodedParamName = "passwordEncoded";
if (command.hasParameter(passwordParamName)) { if (command.hasParameter(passwordParamName)) {
if (command.isChangeInPasswordParameterNamed(passwordParamName, if (command.isChangeInPasswordParameterNamed(passwordParamName, this.password, platformPasswordEncoder, getId())) {
this.password, platformPasswordEncoder, getId())) { final String passwordEncodedValue = command.passwordValueOfParameterNamed(passwordParamName, platformPasswordEncoder,
final String passwordEncodedValue = command getId());
.passwordValueOfParameterNamed(passwordParamName, actualChanges.put(passwordEncodedParamName, passwordEncodedValue);
platformPasswordEncoder, getId());
actualChanges.put(passwordEncodedParamName,
passwordEncodedValue);
updatePassword(passwordEncodedValue); updatePassword(passwordEncodedValue);
} }
} }
if (command.hasParameter(passwordEncodedParamName)) { if (command.hasParameter(passwordEncodedParamName)) {
if (command.isChangeInStringParameterNamed( if (command.isChangeInStringParameterNamed(passwordEncodedParamName, this.password)) {
passwordEncodedParamName, this.password)) { final String newValue = command.stringValueOfParameterNamed(passwordEncodedParamName);
final String newValue = command
.stringValueOfParameterNamed(passwordEncodedParamName);
actualChanges.put(passwordEncodedParamName, newValue); actualChanges.put(passwordEncodedParamName, newValue);
updatePassword(newValue); updatePassword(newValue);
} }
} }
final String officeIdParamName = "officeId"; final String officeIdParamName = "officeId";
if (command.isChangeInLongParameterNamed(officeIdParamName, if (command.isChangeInLongParameterNamed(officeIdParamName, this.office.getId())) {
this.office.getId())) { final Long newValue = command.longValueOfParameterNamed(officeIdParamName);
final Long newValue = command
.longValueOfParameterNamed(officeIdParamName);
actualChanges.put(officeIdParamName, newValue); actualChanges.put(officeIdParamName, newValue);
} }
final String rolesParamName = "roles"; final String rolesParamName = "roles";
if (command.isChangeInArrayParameterNamed(rolesParamName, if (command.isChangeInArrayParameterNamed(rolesParamName, getRolesAsIdStringArray())) {
getRolesAsIdStringArray())) { final String[] newValue = command.arrayValueOfParameterNamed(rolesParamName);
final String[] newValue = command
.arrayValueOfParameterNamed(rolesParamName);
actualChanges.put(rolesParamName, newValue); actualChanges.put(rolesParamName, newValue);
} }
final String usernameParamName = "username"; final String usernameParamName = "username";
if (command.isChangeInStringParameterNamed(usernameParamName, if (command.isChangeInStringParameterNamed(usernameParamName, this.username)) {
this.username)) { final String newValue = command.stringValueOfParameterNamed(usernameParamName);
final String newValue = command
.stringValueOfParameterNamed(usernameParamName);
actualChanges.put(usernameParamName, newValue); actualChanges.put(usernameParamName, newValue);
this.username = newValue; this.username = newValue;
} }
final String firstnameParamName = "firstname"; final String firstnameParamName = "firstname";
if (command.isChangeInStringParameterNamed(firstnameParamName, if (command.isChangeInStringParameterNamed(firstnameParamName, this.firstname)) {
this.firstname)) { final String newValue = command.stringValueOfParameterNamed(firstnameParamName);
final String newValue = command
.stringValueOfParameterNamed(firstnameParamName);
actualChanges.put(firstnameParamName, newValue); actualChanges.put(firstnameParamName, newValue);
this.firstname = newValue; this.firstname = newValue;
} }
final String lastnameParamName = "lastname"; final String lastnameParamName = "lastname";
if (command.isChangeInStringParameterNamed(lastnameParamName, if (command.isChangeInStringParameterNamed(lastnameParamName, this.lastname)) {
this.lastname)) { final String newValue = command.stringValueOfParameterNamed(lastnameParamName);
final String newValue = command
.stringValueOfParameterNamed(lastnameParamName);
actualChanges.put(lastnameParamName, newValue); actualChanges.put(lastnameParamName, newValue);
this.lastname = newValue; this.lastname = newValue;
} }
final String emailParamName = "email"; final String emailParamName = "email";
if (command.isChangeInStringParameterNamed(emailParamName, this.email)) { if (command.isChangeInStringParameterNamed(emailParamName, this.email)) {
final String newValue = command final String newValue = command.stringValueOfParameterNamed(emailParamName);
.stringValueOfParameterNamed(emailParamName);
actualChanges.put(emailParamName, newValue); actualChanges.put(emailParamName, newValue);
this.email = newValue; this.email = newValue;
} }
@@ -292,8 +268,7 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
for (final Role role : this.roles) { for (final Role role : this.roles) {
final Collection<Permission> permissions = role.getPermissions(); final Collection<Permission> permissions = role.getPermissions();
for (final Permission permission : permissions) { for (final Permission permission : permissions) {
grantedAuthorities.add(new SimpleGrantedAuthority(permission grantedAuthorities.add(new SimpleGrantedAuthority(permission.getCode()));
.getCode()));
} }
} }
return grantedAuthorities; return grantedAuthorities;
@@ -371,32 +346,23 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
public boolean hasNotPermissionForReport(final String reportName) { public boolean hasNotPermissionForReport(final String reportName) {
if (hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", if (hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", "REPORTING_SUPER_USER", "READ_" + reportName)) { return true; }
"REPORTING_SUPER_USER", "READ_" + reportName)) {
return true;
}
return false; return false;
} }
public boolean hasNotPermissionForDatatable(final String datatable, public boolean hasNotPermissionForDatatable(final String datatable, final String accessType) {
final String accessType) {
final String matchPermission = accessType + "_" + datatable; final String matchPermission = accessType + "_" + datatable;
if (accessType.equalsIgnoreCase("READ")) { if (accessType.equalsIgnoreCase("READ")) {
if (hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", if (hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", matchPermission)) { return true; }
matchPermission)) {
return true;
}
return false; return false;
} }
if (hasNotPermissionForAnyOf("ALL_FUNCTIONS", matchPermission)) { if (hasNotPermissionForAnyOf("ALL_FUNCTIONS", matchPermission)) { return true; }
return true;
}
return false; return false;
} }
@@ -415,14 +381,10 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
public void validateHasReadPermission(final String resourceType) { public void validateHasReadPermission(final String resourceType) {
final String authorizationMessage = "User has no authority to view " final String authorizationMessage = "User has no authority to view " + resourceType.toLowerCase() + "s";
+ resourceType.toLowerCase() + "s";
final String matchPermission = "READ_" + resourceType.toUpperCase(); final String matchPermission = "READ_" + resourceType.toUpperCase();
if (!hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", if (!hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", matchPermission)) { return; }
matchPermission)) {
return;
}
throw new NoAuthorizationException(authorizationMessage); throw new NoAuthorizationException(authorizationMessage);
} }
@@ -476,42 +438,41 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
return hasAtLeastOneOf; return hasAtLeastOneOf;
} }
public void validateHasPermissionTo(final String function, public void validateHasPermissionTo(final String function, final List<String> allowedPermissions) {
final List<String> allowedPermissions) {
if (hasNotAnyPermission(allowedPermissions)) { if (hasNotAnyPermission(allowedPermissions)) {
final String authorizationMessage = "User has no authority to: " final String authorizationMessage = "User has no authority to: " + function;
+ function;
throw new NoAuthorizationException(authorizationMessage); throw new NoAuthorizationException(authorizationMessage);
} }
} }
public void validateHasPermissionTo(final String function) { public void validateHasPermissionTo(final String function) {
if (hasNotPermissionTo(function)) { if (hasNotPermissionTo(function)) {
final String authorizationMessage = "User has no authority to: " final String authorizationMessage = "User has no authority to: " + function;
+ function; logger.info("Unauthorized access: userId: " + getId() + " action: " + function + " allowed: " + getAuthorities());
logger.info("Unauthorized access: userId: " + getId() + " action: "
+ function + " allowed: " + getAuthorities());
throw new NoAuthorizationException(authorizationMessage); throw new NoAuthorizationException(authorizationMessage);
} }
} }
public void validateHasReadPermission(final String function, final Long userId) {
if ("USER".equalsIgnoreCase(function) && userId.equals(getId())) {
// abstain from validation as user allowed fetch their own data no matter what permissions they have.
} else {
validateHasPermissionTo(function);
}
}
public void validateHasCheckerPermissionTo(final String function) { public void validateHasCheckerPermissionTo(final String function) {
final String checkerPermissionName = function.toUpperCase() final String checkerPermissionName = function.toUpperCase() + "_CHECKER";
+ "_CHECKER"; if (hasNotPermissionTo("CHECKER_SUPER_USER") && hasNotPermissionTo(checkerPermissionName)) {
if (hasNotPermissionTo("CHECKER_SUPER_USER") final String authorizationMessage = "User has no authority to be a checker for: " + function;
&& hasNotPermissionTo(checkerPermissionName)) {
final String authorizationMessage = "User has no authority to be a checker for: "
+ function;
throw new NoAuthorizationException(authorizationMessage); throw new NoAuthorizationException(authorizationMessage);
} }
} }
public void validateHasDatatableReadPermission(final String datatable) { public void validateHasDatatableReadPermission(final String datatable) {
if (hasNotPermissionForDatatable(datatable, "READ")) { if (hasNotPermissionForDatatable(datatable, "READ")) { throw new NoAuthorizationException("Not authorised to read datatable: "
throw new NoAuthorizationException( + datatable); }
"Not authorised to read datatable: " + datatable);
}
} }
public Long getStaffId() { public Long getStaffId() {