MIFOSX-751 password reset functionality added by Musoni
This commit is contained in:
committed by
Vishwas Babu A J
parent
36fcb9c069
commit
fe510e8e1a
+21
-11
@@ -10225,9 +10225,17 @@ GET https://DomainName/api/v1/configurations
|
||||
{
|
||||
"globalConfiguration": [
|
||||
{
|
||||
"name": "maker-checker",
|
||||
"enabled": false
|
||||
}
|
||||
"name": "maker-checker",
|
||||
"enabled": true,
|
||||
"value": 0,
|
||||
"id": 1
|
||||
},
|
||||
{
|
||||
"name": "amazon-S3",
|
||||
"enabled": false,
|
||||
"value": 0,
|
||||
"id": 2
|
||||
},
|
||||
]
|
||||
}
|
||||
</code>
|
||||
@@ -10242,22 +10250,24 @@ GET https://DomainName/api/v1/configurations
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
PUT https://DomainName/api/v1/configurations?maker-checker=false
|
||||
PUT https://DomainName/api/v1/configurations/9
|
||||
</code>
|
||||
<code class="method-request">
|
||||
PUT configurations
|
||||
Content-Type: application/json
|
||||
Request Body: { }
|
||||
Request Body: {
|
||||
"enabled":"true",
|
||||
"value":2
|
||||
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"changes": {
|
||||
"globalConfiguration": {
|
||||
"maker-checker": false
|
||||
"resourceId": 9,
|
||||
"changes": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
</code>
|
||||
} </code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
INSERT INTO `c_configuration` (`id`, `name`, `value`, `enabled`) VALUES (NULL, 'force-password-reset-days', '0', '0');
|
||||
|
||||
ALTER TABLE `m_appuser` ADD `last_time_password_updated` DATE NOT NULL ,
|
||||
ADD INDEX ( `last_time_password_updated` ) ;
|
||||
|
||||
UPDATE `m_appuser` SET `last_time_password_updated` = NOW() WHERE `m_appuser`.`last_time_password_updated` ='0000-00-00';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `m_appuser_previews_passwords` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint(20) NOT NULL,
|
||||
`password` varchar(255) NOT NULL,
|
||||
`removal_date` date NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
|
||||
|
||||
ALTER TABLE m_appuser_previews_passwords
|
||||
ADD FOREIGN KEY (user_id) REFERENCES m_appuser(id);
|
||||
+4
-3
@@ -54,11 +54,12 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateGlobalConfiguration() {
|
||||
public CommandWrapperBuilder updateGlobalConfiguration(final Long configId) {
|
||||
this.actionName = "UPDATE";
|
||||
this.entityName = "CONFIGURATION";
|
||||
this.entityId = null;
|
||||
this.href = "/configurations";
|
||||
this.entityId = configId;
|
||||
|
||||
this.href = "/configurations/"+configId;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -47,7 +47,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
||||
|
||||
boolean isApprovedByChecker = false;
|
||||
// check if is update of own account details
|
||||
if (wrapper.isUpdateOfOwnUserDetails(this.context.authenticatedUser().getId())) {
|
||||
if (wrapper.isUpdateOfOwnUserDetails(this.context.authenticatedUser(wrapper).getId())) {
|
||||
// then allow this operation to proceed.
|
||||
// maker checker doesnt mean anything here.
|
||||
isApprovedByChecker = true; // set to true in case permissions have
|
||||
@@ -56,7 +56,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
||||
} else {
|
||||
// if not user changing their own details - check user has
|
||||
// permission to perform specific task.
|
||||
this.context.authenticatedUser().validateHasPermissionTo(wrapper.getTaskPermissionName());
|
||||
this.context.authenticatedUser(wrapper).validateHasPermissionTo(wrapper.getTaskPermissionName());
|
||||
}
|
||||
validateIsUpdateAllowed();
|
||||
|
||||
@@ -72,6 +72,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
||||
result = this.processAndLogCommandService.processAndLogCommand(wrapper, command, isApprovedByChecker);
|
||||
} catch (final RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
|
||||
|
||||
|
||||
result = this.processAndLogCommandService.logCommand(e.getCommandSourceResult());
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
final NewCommandSourceHandler handler = findCommandHandler(wrapper);
|
||||
final CommandProcessingResult result = handler.processCommand(command);
|
||||
|
||||
final AppUser maker = this.context.authenticatedUser();
|
||||
final AppUser maker = this.context.authenticatedUser(wrapper);
|
||||
|
||||
CommandSource commandSourceResult = null;
|
||||
if (command.commandId() != null) {
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package org.mifosplatform.infrastructure.configuration.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Cieyou on 1/16/14.
|
||||
*/
|
||||
public class GlobalConfigurationApiConstant {
|
||||
|
||||
|
||||
public static final String enabled = "enabled";
|
||||
public static final String value = "value";
|
||||
public static final String id ="id";
|
||||
public static final String CONFIGURATION_RESOURCE_NAME = "globalConfiguration";
|
||||
|
||||
|
||||
public static final Set<String> UPDATE_CONFIGURATION_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(enabled,
|
||||
value));
|
||||
|
||||
}
|
||||
+8
-15
@@ -11,12 +11,9 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
@@ -76,25 +73,21 @@ public class GlobalConfigurationApiResource {
|
||||
return this.toApiJsonSerializer.serialize(settings, configurationData, this.RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
|
||||
@PUT
|
||||
@Path("{configId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String updateConfiguration(@Context final UriInfo uriInfo) {
|
||||
public String updateConfiguration(@PathParam("configId") final Long configId,final String apiRequestBodyAsJson) {
|
||||
|
||||
final Map<String, String> configurationParameters = ApiParameterHelper.asMap(uriInfo.getQueryParameters());
|
||||
|
||||
final Map<String, Object> globalConfiguration = new HashMap<String, Object>();
|
||||
globalConfiguration.put("globalConfiguration", configurationParameters);
|
||||
|
||||
final String apiRequestJson = this.toApiJsonSerializer.serialize(globalConfiguration);
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||
.updateGlobalConfiguration() //
|
||||
.withJson(apiRequestJson) //
|
||||
.updateGlobalConfiguration(configId) //
|
||||
.withJson(apiRequestBodyAsJson) //
|
||||
.build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package org.mifosplatform.infrastructure.configuration.data;
|
||||
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mifosplatform.infrastructure.configuration.api.GlobalConfigurationApiConstant.*;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Created by Cieyou on 1/16/14.
|
||||
*/
|
||||
@Component
|
||||
public class GlobalConfigurationDataValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public GlobalConfigurationDataValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateForUpdate(final JsonCommand command) {
|
||||
final String json = command.json();
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,UPDATE_CONFIGURATION_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CONFIGURATION_RESOURCE_NAME);
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
final JsonObject jsonElement = element.getAsJsonObject();
|
||||
|
||||
if(this.fromApiJsonHelper.parameterExists(enabled, element))
|
||||
{
|
||||
final boolean enabledBool = this.fromApiJsonHelper.extractBooleanNamed(enabled,element);
|
||||
baseDataValidator.reset().parameter(enabled).value(enabledBool).validateForBooleanValue();
|
||||
}
|
||||
|
||||
if(this.fromApiJsonHelper.parameterExists(value, element))
|
||||
{
|
||||
final Long valueStr = this.fromApiJsonHelper.extractLongNamed(value,element);
|
||||
baseDataValidator.reset().parameter(enabled).value(valueStr).zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
|
||||
}
|
||||
}
|
||||
+10
@@ -16,10 +16,20 @@ public class GlobalConfigurationPropertyData {
|
||||
private final boolean enabled;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long value;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
|
||||
public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value) {
|
||||
this.name = name;
|
||||
this.enabled = enabled;
|
||||
this.value = value;
|
||||
this.id = null;
|
||||
}
|
||||
|
||||
public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value, final Long id) {
|
||||
this.name = name;
|
||||
this.enabled = enabled;
|
||||
this.value = value;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
+4
@@ -28,4 +28,8 @@ public interface ConfigurationDomainService {
|
||||
void updateCache(CacheType cacheType);
|
||||
|
||||
Long retrievePenaltyWaitPeriod();
|
||||
|
||||
boolean isPasswordForcedResetEnable();
|
||||
|
||||
Long retrievePasswordLiveTime();
|
||||
}
|
||||
+20
@@ -120,4 +120,24 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
|
||||
if (property == null) { throw new GlobalConfigurationPropertyNotFoundException(propertyName); }
|
||||
return property.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPasswordForcedResetEnable(){
|
||||
|
||||
final String propertyName ="force-password-reset-days";
|
||||
final GlobalConfigurationProperty property= this.globalConfigurationRepository.findOneByName(propertyName);
|
||||
if (property == null) { throw new GlobalConfigurationPropertyNotFoundException(propertyName); }
|
||||
|
||||
return property.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long retrievePasswordLiveTime(){
|
||||
|
||||
final String propertyName ="force-password-reset-days";
|
||||
final GlobalConfigurationProperty property= this.globalConfigurationRepository.findOneByName(propertyName);
|
||||
if (property == null) { throw new GlobalConfigurationPropertyNotFoundException(propertyName); }
|
||||
|
||||
return property.getValue();
|
||||
}
|
||||
}
|
||||
+36
-1
@@ -5,11 +5,18 @@
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.configuration.domain;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity
|
||||
@Table(name = "c_configuration")
|
||||
@@ -22,7 +29,7 @@ public class GlobalConfigurationProperty extends AbstractPersistable<Long> {
|
||||
private boolean enabled;
|
||||
|
||||
@Column(name= "value", nullable= true)
|
||||
private final Long value;
|
||||
private Long value;
|
||||
|
||||
protected GlobalConfigurationProperty() {
|
||||
this.name = null;
|
||||
@@ -50,4 +57,32 @@ public class GlobalConfigurationProperty extends AbstractPersistable<Long> {
|
||||
return updated;
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command)
|
||||
{
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7);
|
||||
|
||||
// final String localeAsInput = command.locale();
|
||||
|
||||
// final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
// final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("c");
|
||||
|
||||
final String enabledParamName = "enabled";
|
||||
if (command.isChangeInBooleanParameterNamed(enabledParamName, this.enabled)) {
|
||||
final Boolean newValue = command.booleanPrimitiveValueOfParameterNamed (enabledParamName);
|
||||
actualChanges.put(enabledParamName, newValue);
|
||||
this.enabled = newValue;
|
||||
}
|
||||
|
||||
final String valueParamName = "value";
|
||||
if (command.isChangeInLongParameterNamed(valueParamName, this.value)) {
|
||||
final Long newValue = command.longValueOfParameterNamed(valueParamName);
|
||||
actualChanges.put(valueParamName, newValue);
|
||||
this.value = newValue;
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+4
@@ -16,4 +16,8 @@ public class GlobalConfigurationPropertyNotFoundException extends AbstractPlatfo
|
||||
public GlobalConfigurationPropertyNotFoundException(final String propertyName) {
|
||||
super("error.msg.configuration.property.invalid", "Configuration property `" + propertyName + "` does not exist", propertyName);
|
||||
}
|
||||
|
||||
public GlobalConfigurationPropertyNotFoundException(final Long configId) {
|
||||
super("error.msg.configuration.id.invalid", "Configuration identifier `" + configId + "` does not exist", configId);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class UpdateGlobalConfigurationCommandHandler implements NewCommandSource
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.update(command);
|
||||
return this.writePlatformService.update(command.entityId(),command);
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -38,7 +38,7 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final String sql = "SELECT c.name, c.enabled, c.value FROM c_configuration c order by c.id";
|
||||
final String sql = "SELECT c.id, c.name, c.enabled, c.value FROM c_configuration c order by c.id";
|
||||
final List<GlobalConfigurationPropertyData> globalConfiguration = this.jdbcTemplate.query(sql, this.rm, new Object[] {});
|
||||
|
||||
return new GlobalConfigurationData(globalConfiguration);
|
||||
@@ -52,8 +52,11 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
|
||||
final String name = rs.getString("name");
|
||||
final boolean enabled = rs.getBoolean("enabled");
|
||||
final Long value = rs.getLong("value");
|
||||
final Long id = rs.getLong("id");
|
||||
|
||||
return new GlobalConfigurationPropertyData(name, enabled,value);
|
||||
return new GlobalConfigurationPropertyData(name, enabled,value,id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+3
-1
@@ -10,5 +10,7 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface GlobalConfigurationWritePlatformService {
|
||||
|
||||
CommandProcessingResult update(JsonCommand command);
|
||||
//CommandProcessingResult update(JsonCommand command);
|
||||
|
||||
CommandProcessingResult update(Long configId, JsonCommand command);
|
||||
}
|
||||
+74
-21
@@ -16,61 +16,114 @@ import org.mifosplatform.infrastructure.configuration.serialization.GlobalConfig
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.mifosplatform.infrastructure.configuration.data.GlobalConfigurationDataValidator;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
|
||||
@Service
|
||||
public class GlobalConfigurationWritePlatformServiceJpaRepositoryImpl implements GlobalConfigurationWritePlatformService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(GlobalConfigurationWritePlatformServiceJpaRepositoryImpl.class);
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final GlobalConfigurationRepository repository;
|
||||
private final GlobalConfigurationCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||
private final GlobalConfigurationDataValidator globalConfigurationDataValidator ;
|
||||
|
||||
@Autowired
|
||||
public GlobalConfigurationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final GlobalConfigurationRepository codeRepository,
|
||||
final GlobalConfigurationCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
|
||||
final GlobalConfigurationCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||
final GlobalConfigurationDataValidator dataValidator) {
|
||||
this.context = context;
|
||||
this.repository = codeRepository;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.globalConfigurationDataValidator = dataValidator;
|
||||
|
||||
}
|
||||
|
||||
// @Transactional
|
||||
// @Override
|
||||
// public CommandProcessingResult update(final JsonCommand command) {
|
||||
//
|
||||
// this.context.authenticatedUser();
|
||||
//
|
||||
// final UpdateGlobalConfigurationCommand configurationCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
|
||||
//
|
||||
// final Map<String, Boolean> params = configurationCommand.getGlobalConfiguration();
|
||||
//
|
||||
// final Map<String, Object> changes = new LinkedHashMap<String, Object>(params.size());
|
||||
// final Map<String, Boolean> propertiesMap = new LinkedHashMap<String, Boolean>(1);
|
||||
// for (final String propertyName : params.keySet()) {
|
||||
// final GlobalConfigurationProperty property = retrieveBy(propertyName);
|
||||
//
|
||||
// final Boolean value = params.get(propertyName);
|
||||
// final boolean updated = property.updateTo(value);
|
||||
//
|
||||
// if (updated) {
|
||||
// propertiesMap.put(propertyName, value);
|
||||
// this.repository.save(property);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!propertiesMap.isEmpty()) {
|
||||
// changes.put("globalConfiguration", propertiesMap);
|
||||
// }
|
||||
//
|
||||
// return new CommandProcessingResultBuilder().withCommandId(command.commandId()).with(changes).build();
|
||||
// }
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult update(final JsonCommand command) {
|
||||
public CommandProcessingResult update(final Long configId , final JsonCommand command) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final UpdateGlobalConfigurationCommand configurationCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
|
||||
try {
|
||||
this.globalConfigurationDataValidator.validateForUpdate(command);
|
||||
|
||||
final Map<String, Boolean> params = configurationCommand.getGlobalConfiguration();
|
||||
final GlobalConfigurationProperty configItemForUpdate = this.repository.findOne(configId);
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>(params.size());
|
||||
final Map<String, Boolean> propertiesMap = new LinkedHashMap<String, Boolean>(1);
|
||||
for (final String propertyName : params.keySet()) {
|
||||
final GlobalConfigurationProperty property = retrieveBy(propertyName);
|
||||
|
||||
final Boolean value = params.get(propertyName);
|
||||
final boolean updated = property.updateTo(value);
|
||||
|
||||
if (updated) {
|
||||
propertiesMap.put(propertyName, value);
|
||||
this.repository.save(property);
|
||||
if (configItemForUpdate == null) {
|
||||
throw new GlobalConfigurationPropertyNotFoundException(configId);
|
||||
}
|
||||
|
||||
final Map<String, Object> changes = configItemForUpdate.update(command);
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
this.repository.save(configItemForUpdate);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(configId).with(changes).build();
|
||||
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
handleDataIntegrityIssues(command, dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
|
||||
if (!propertiesMap.isEmpty()) {
|
||||
changes.put("globalConfiguration", propertiesMap);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).with(changes).build();
|
||||
}
|
||||
}
|
||||
|
||||
private GlobalConfigurationProperty retrieveBy(final String propertyName) {
|
||||
final GlobalConfigurationProperty property = this.repository.findOneByName(propertyName);
|
||||
if (property == null) { throw new GlobalConfigurationPropertyNotFoundException(propertyName); }
|
||||
return property;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guaranteed to throw an exception no matter what the data integrity issue
|
||||
* is.
|
||||
*/
|
||||
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
|
||||
|
||||
final Throwable realCause = dve.getMostSpecificCause();
|
||||
logger.error(dve.getMessage(), dve);
|
||||
throw new PlatformDataIntegrityException("error.msg.globalConfiguration.unknown.data.integrity.issue",
|
||||
"Unknown data integrity issue with resource: " + realCause.getMessage());
|
||||
}
|
||||
}
|
||||
+22
-3
@@ -18,9 +18,13 @@ import javax.ws.rs.core.MediaType;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.security.data.AuthenticatedUserData;
|
||||
import org.mifosplatform.infrastructure.security.exception.ResetPasswordException;
|
||||
import org.mifosplatform.infrastructure.security.service.SpringSecurityPlatformSecurityContext;
|
||||
import org.mifosplatform.useradministration.data.RoleData;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.mifosplatform.useradministration.domain.Role;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
@@ -39,13 +43,17 @@ public class AuthenticationApiResource {
|
||||
|
||||
private final DaoAuthenticationProvider customAuthenticationProvider;
|
||||
private final ToApiJsonSerializer<AuthenticatedUserData> apiJsonSerializerService;
|
||||
private final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext;
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(AuthenticationApiResource.class);
|
||||
|
||||
@Autowired
|
||||
public AuthenticationApiResource(
|
||||
@Qualifier("customAuthenticationProvider") final DaoAuthenticationProvider customAuthenticationProvider,
|
||||
final ToApiJsonSerializer<AuthenticatedUserData> apiJsonSerializerService) {
|
||||
final ToApiJsonSerializer<AuthenticatedUserData> apiJsonSerializerService,final SpringSecurityPlatformSecurityContext springSecurityPlatformSecurityContext) {
|
||||
this.customAuthenticationProvider = customAuthenticationProvider;
|
||||
this.apiJsonSerializerService = apiJsonSerializerService;
|
||||
this.springSecurityPlatformSecurityContext = springSecurityPlatformSecurityContext;
|
||||
}
|
||||
|
||||
@POST
|
||||
@@ -72,6 +80,8 @@ public class AuthenticationApiResource {
|
||||
roles.add(role.toData());
|
||||
}
|
||||
|
||||
|
||||
|
||||
final Long officeId = principal.getOffice().getId();
|
||||
final String officeName = principal.getOffice().getName();
|
||||
|
||||
@@ -80,8 +90,17 @@ public class AuthenticationApiResource {
|
||||
|
||||
final EnumOptionData organisationalRole = principal.organisationalRoleData();
|
||||
|
||||
authenticatedUserData = new AuthenticatedUserData(username, officeId, officeName, staffId, staffDisplayName,
|
||||
organisationalRole, roles, permissions, principal.getId(), new String(base64EncodedAuthenticationKey));
|
||||
if(this.springSecurityPlatformSecurityContext.doesPasswordHasToBeRenewed(principal)){
|
||||
//throw new ResetPasswordException(principal.getId());
|
||||
authenticatedUserData = new AuthenticatedUserData(username,principal.getId(), new String(base64EncodedAuthenticationKey));
|
||||
}
|
||||
else{
|
||||
|
||||
authenticatedUserData = new AuthenticatedUserData(username, officeId, officeName, staffId, staffDisplayName,
|
||||
organisationalRole, roles, permissions, principal.getId(), new String(base64EncodedAuthenticationKey));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return this.apiJsonSerializerService.serialize(authenticatedUserData);
|
||||
|
||||
+20
@@ -38,6 +38,9 @@ public class AuthenticatedUserData {
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<String> permissions;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean shouldRenewPassword;
|
||||
|
||||
public AuthenticatedUserData(final String username, final Collection<String> permissions) {
|
||||
this.username = username;
|
||||
this.userId = null;
|
||||
@@ -50,6 +53,7 @@ public class AuthenticatedUserData {
|
||||
this.organisationalRole = null;
|
||||
this.roles = null;
|
||||
this.permissions = permissions;
|
||||
this.shouldRenewPassword = false;
|
||||
}
|
||||
|
||||
public AuthenticatedUserData(final String username, final Long officeId, final String officeName, final Long staffId,
|
||||
@@ -66,5 +70,21 @@ public class AuthenticatedUserData {
|
||||
this.authenticated = true;
|
||||
this.roles = roles;
|
||||
this.permissions = permissions;
|
||||
this.shouldRenewPassword = false;
|
||||
}
|
||||
|
||||
public AuthenticatedUserData(final String username, final Long userId, final String base64EncodedAuthenticationKey) {
|
||||
this.username = username;
|
||||
this.officeId = null;
|
||||
this.officeName = null;
|
||||
this.staffId = null;
|
||||
this.staffDisplayName = null;
|
||||
this.organisationalRole = null;
|
||||
this.userId = userId;
|
||||
this.base64EncodedAuthenticationKey = base64EncodedAuthenticationKey;
|
||||
this.authenticated = true;
|
||||
this.roles = null;
|
||||
this.permissions = null;
|
||||
this.shouldRenewPassword = true;
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.security.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformServiceUnavailableException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} that is thrown in the case where a user does not
|
||||
* have sufficient authorization to execute operation on platform.
|
||||
*/
|
||||
public class ResetPasswordException extends PlatformApiDataValidationException {
|
||||
|
||||
|
||||
public ResetPasswordException(final Long userId) {
|
||||
|
||||
super(
|
||||
"error.msg.password.outdated",
|
||||
"The password of the user with id "+userId+" has expired, please reset it it",
|
||||
new ArrayList<ApiParameterError>(){
|
||||
{
|
||||
add (ApiParameterError.parameterError(
|
||||
"error.msg.password.outdated",
|
||||
"The password of the user with id "+userId+" has expired, please reset it it",
|
||||
"userId",userId)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+6
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.security.service;
|
||||
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
|
||||
public interface PlatformSecurityContext {
|
||||
@@ -14,4 +16,8 @@ public interface PlatformSecurityContext {
|
||||
void validateAccessRights(String resourceOfficeHierarchy);
|
||||
|
||||
String officeHierarchy();
|
||||
|
||||
boolean doesPasswordHasToBeRenewed(AppUser currentUser);
|
||||
|
||||
AppUser authenticatedUser(CommandWrapper commandWrapper);
|
||||
}
|
||||
+105
@@ -5,23 +5,56 @@
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.security.service;
|
||||
|
||||
import com.sun.jersey.api.spring.Autowire;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException;
|
||||
import org.mifosplatform.infrastructure.security.exception.ResetPasswordException;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.mifosplatform.useradministration.exception.UnAuthenticatedUserException;
|
||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainServiceJpa;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import sun.print.resources.serviceui_zh_TW;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Wrapper around spring security's {@link SecurityContext} for extracted the
|
||||
* current authenticated {@link AppUser}.
|
||||
*/
|
||||
|
||||
@Service
|
||||
public class SpringSecurityPlatformSecurityContext implements PlatformSecurityContext {
|
||||
|
||||
private final ConfigurationDomainService configurationDomainService ;
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(SpringSecurityPlatformSecurityContext.class);
|
||||
|
||||
public static final List<CommandWrapper> EXEMPT_FROM_PASSWORD_RESET_CHECK = new ArrayList<CommandWrapper>(){
|
||||
{
|
||||
add(new CommandWrapperBuilder().updateUser(null).build());
|
||||
}
|
||||
};
|
||||
|
||||
@Autowired
|
||||
SpringSecurityPlatformSecurityContext(final ConfigurationDomainService configurationDomainService){
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppUser authenticatedUser() {
|
||||
|
||||
AppUser currentUser = null;
|
||||
final SecurityContext context = SecurityContextHolder.getContext();
|
||||
if (context != null) {
|
||||
@@ -33,9 +66,34 @@ public class SpringSecurityPlatformSecurityContext implements PlatformSecurityCo
|
||||
|
||||
if (currentUser == null) { throw new UnAuthenticatedUserException(); }
|
||||
|
||||
|
||||
if(this.doesPasswordHasToBeRenewed(currentUser)) { throw new ResetPasswordException(currentUser.getId());}
|
||||
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
public AppUser authenticatedUser(CommandWrapper commandWrapper)
|
||||
{
|
||||
|
||||
AppUser currentUser = null;
|
||||
final SecurityContext context = SecurityContextHolder.getContext();
|
||||
if (context != null) {
|
||||
final Authentication auth = context.getAuthentication();
|
||||
if (auth != null) {
|
||||
currentUser = (AppUser) auth.getPrincipal();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (currentUser == null) { throw new UnAuthenticatedUserException(); }
|
||||
|
||||
if(this.shouldCheckForPasswordForceReset(commandWrapper) && this.doesPasswordHasToBeRenewed(currentUser)) { throw new ResetPasswordException(currentUser.getId());}
|
||||
|
||||
return currentUser;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void validateAccessRights(final String resourceOfficeHierarchy) {
|
||||
|
||||
@@ -51,4 +109,51 @@ public class SpringSecurityPlatformSecurityContext implements PlatformSecurityCo
|
||||
public String officeHierarchy() {
|
||||
return authenticatedUser().getOffice().getHierarchy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesPasswordHasToBeRenewed(AppUser currentUser )
|
||||
{
|
||||
|
||||
if( this.configurationDomainService.isPasswordForcedResetEnable()){
|
||||
|
||||
Long passwordDurationDays = this.configurationDomainService.retrievePasswordLiveTime();
|
||||
final Date passWordLastUpdateDate = currentUser .getLastTimePasswordUpdated();
|
||||
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTime(passWordLastUpdateDate);
|
||||
c.add(Calendar.DATE,passwordDurationDays.intValue());
|
||||
|
||||
final Date passwordExpirationDate = c.getTime();
|
||||
|
||||
if(DateUtils.getDateOfTenant().after(passwordExpirationDate)){
|
||||
|
||||
return true ;
|
||||
}
|
||||
else { return false; }
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean shouldCheckForPasswordForceReset(CommandWrapper commandWrapper)
|
||||
{
|
||||
for( CommandWrapper commandItem : this.EXEMPT_FROM_PASSWORD_RESET_CHECK )
|
||||
{
|
||||
if(commandItem.actionName().equals(commandWrapper.actionName())
|
||||
&& commandItem.getEntityName().equals(commandWrapper.getEntityName()))
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.mifosplatform.useradministration.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Cieyou on 1/16/14.
|
||||
*/
|
||||
public class AppUserApiConstant {
|
||||
|
||||
public static final int numberOfPreviousPasswords = 3;
|
||||
|
||||
}
|
||||
+40
-9
@@ -12,16 +12,9 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import javax.persistence.*;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
@@ -37,6 +30,8 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_appuser", uniqueConstraints = @UniqueConstraint(columnNames = { "username" }, name = "username_org"))
|
||||
@@ -89,6 +84,10 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
@JoinTable(name = "m_appuser_role", joinColumns = @JoinColumn(name = "appuser_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
|
||||
private Set<Role> roles;
|
||||
|
||||
@Column(name = "last_time_password_updated")
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date lastTimePasswordUpdated;
|
||||
|
||||
public static AppUser fromJson(final Office userOffice, final Set<Role> allRoles, final JsonCommand command) {
|
||||
|
||||
final String username = command.stringValueOfParameterNamed("username");
|
||||
@@ -137,6 +136,7 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
this.enabled = user.isEnabled();
|
||||
this.roles = roles;
|
||||
this.firstTimeLoginRemaining = true;
|
||||
this.lastTimePasswordUpdated = DateUtils.getDateOfTenant();
|
||||
}
|
||||
|
||||
public EnumOptionData organisationalRoleData() {
|
||||
@@ -150,6 +150,8 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
public void updatePassword(final String encodePassword) {
|
||||
this.password = encodePassword;
|
||||
this.firstTimeLoginRemaining = false;
|
||||
this.lastTimePasswordUpdated = DateUtils.getDateOfTenant();
|
||||
|
||||
}
|
||||
|
||||
public void changeOffice(final Office differentOffice) {
|
||||
@@ -324,6 +326,8 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
return this.office;
|
||||
}
|
||||
|
||||
public Date getLastTimePasswordUpdated(){ return this.lastTimePasswordUpdated; }
|
||||
|
||||
public boolean canNotApproveLoanInPast() {
|
||||
return hasNotPermissionForAnyOf("ALL_FUNCTIONS", "APPROVEINPAST_LOAN");
|
||||
}
|
||||
@@ -491,4 +495,31 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
}
|
||||
return staffDisplayName;
|
||||
}
|
||||
|
||||
public String getEncodedPassword(final JsonCommand command,final PlatformPasswordEncoder platformPasswordEncoder)
|
||||
{
|
||||
final String passwordParamName = "password";
|
||||
final String passwordEncodedParamName = "passwordEncoded";
|
||||
String passwordEncodedValue = null;
|
||||
|
||||
if (command.hasParameter(passwordParamName)) {
|
||||
if (command.isChangeInPasswordParameterNamed(passwordParamName, this.password
|
||||
, platformPasswordEncoder,getId())) {
|
||||
|
||||
passwordEncodedValue = command.passwordValueOfParameterNamed(passwordParamName, platformPasswordEncoder,
|
||||
getId());
|
||||
|
||||
}
|
||||
}
|
||||
else if (command.hasParameter(passwordEncodedParamName)) {
|
||||
if (command.isChangeInStringParameterNamed(passwordEncodedParamName, this.password)) {
|
||||
|
||||
passwordEncodedValue = command.stringValueOfParameterNamed(passwordEncodedParamName);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return passwordEncodedValue;
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.useradministration.domain;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_appuser_previews_passwords")
|
||||
public class AppUserPreviewPassword extends AbstractPersistable<Long> {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(AppUserPreviewPassword.class);
|
||||
|
||||
@Column(name = "user_id", nullable = false)
|
||||
private Long userId;
|
||||
|
||||
@Column(name = "removal_date")
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date removalDate;
|
||||
|
||||
@Column(name = "password", nullable = false)
|
||||
private String password;
|
||||
|
||||
|
||||
protected AppUserPreviewPassword() {
|
||||
|
||||
}
|
||||
|
||||
public AppUserPreviewPassword(final AppUser user) {
|
||||
|
||||
this.userId = user.getId();
|
||||
this.password = user.getPassword().trim();
|
||||
this.removalDate = DateUtils.getDateOfTenant();
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return this.password;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.useradministration.domain;
|
||||
|
||||
import org.mifosplatform.infrastructure.security.domain.PlatformUserRepository;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AppUserPreviewPasswordRepository extends JpaRepository<AppUserPreviewPassword, Long>, JpaSpecificationExecutor<AppUserPreviewPassword> {
|
||||
|
||||
// no behaviour added
|
||||
// @Query("SELECT upp FROM AppUserPreviewPassword upp WHERE upp.userId = :userId order by upp.removalDate ASC ")
|
||||
public List<AppUserPreviewPassword> findByUserId(Long userId,Pageable pageable);
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.useradministration.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
|
||||
public class PasswordPreviouslyUsedException extends PlatformApiDataValidationException {
|
||||
|
||||
public PasswordPreviouslyUsedException() {
|
||||
super("error.msg.password.already.used", "The submitted password has already been used in the past",null);
|
||||
}
|
||||
}
|
||||
|
||||
+64
-7
@@ -11,6 +11,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
@@ -23,11 +25,9 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.mifosplatform.useradministration.domain.AppUserRepository;
|
||||
import org.mifosplatform.useradministration.domain.Role;
|
||||
import org.mifosplatform.useradministration.domain.RoleRepository;
|
||||
import org.mifosplatform.useradministration.domain.UserDomainService;
|
||||
import org.mifosplatform.useradministration.api.AppUserApiConstant;
|
||||
import org.mifosplatform.useradministration.domain.*;
|
||||
import org.mifosplatform.useradministration.exception.PasswordPreviouslyUsedException;
|
||||
import org.mifosplatform.useradministration.exception.RoleNotFoundException;
|
||||
import org.mifosplatform.useradministration.exception.UserNotFoundException;
|
||||
import org.slf4j.Logger;
|
||||
@@ -36,6 +36,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Caching;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -52,11 +54,12 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
||||
private final OfficeRepository officeRepository;
|
||||
private final RoleRepository roleRepository;
|
||||
private final UserDataValidator fromApiJsonDeserializer;
|
||||
private final AppUserPreviewPasswordRepository appUserPreviewPasswordRepository;
|
||||
|
||||
@Autowired
|
||||
public AppUserWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final AppUserRepository appUserRepository,
|
||||
final UserDomainService userDomainService, final OfficeRepository officeRepository, final RoleRepository roleRepository,
|
||||
final PlatformPasswordEncoder platformPasswordEncoder, final UserDataValidator fromApiJsonDeserializer) {
|
||||
final PlatformPasswordEncoder platformPasswordEncoder, final UserDataValidator fromApiJsonDeserializer,final AppUserPreviewPasswordRepository appUserPreviewPasswordRepository) {
|
||||
this.context = context;
|
||||
this.appUserRepository = appUserRepository;
|
||||
this.userDomainService = userDomainService;
|
||||
@@ -64,6 +67,7 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
||||
this.roleRepository = roleRepository;
|
||||
this.platformPasswordEncoder = platformPasswordEncoder;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.appUserPreviewPasswordRepository = appUserPreviewPasswordRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -120,13 +124,21 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
||||
public CommandProcessingResult updateUser(final Long userId, final JsonCommand command) {
|
||||
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
|
||||
this.context.authenticatedUser(new CommandWrapperBuilder().updateUser(null).build());
|
||||
|
||||
this.fromApiJsonDeserializer.validateForUpdate(command.json());
|
||||
|
||||
final AppUser userToUpdate = this.appUserRepository.findOne(userId);
|
||||
|
||||
|
||||
if (userToUpdate == null) { throw new UserNotFoundException(userId); }
|
||||
|
||||
|
||||
final AppUserPreviewPassword currentPasswordToSaveAsPreview = getCurrentPasswordToSaveAsPreview(userToUpdate,command);
|
||||
|
||||
|
||||
final Map<String, Object> changes = userToUpdate.update(command, this.platformPasswordEncoder);
|
||||
|
||||
if (changes.containsKey("officeId")) {
|
||||
@@ -146,6 +158,9 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
this.appUserRepository.saveAndFlush(userToUpdate);
|
||||
|
||||
if(currentPasswordToSaveAsPreview!=null) {this.appUserPreviewPasswordRepository.save(currentPasswordToSaveAsPreview);}
|
||||
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -155,10 +170,52 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
||||
.build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
handleDataIntegrityIssues(command, dve);
|
||||
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* encode the new submitted password
|
||||
* retrieve the last n used password
|
||||
* check if the current submitted password, match with one of them
|
||||
* @param user
|
||||
* @param command
|
||||
* @return
|
||||
*/
|
||||
private AppUserPreviewPassword getCurrentPasswordToSaveAsPreview(final AppUser user,final JsonCommand command)
|
||||
{
|
||||
|
||||
final String passWordEncodedValue = user.getEncodedPassword(command,this.platformPasswordEncoder);
|
||||
|
||||
AppUserPreviewPassword currentPasswordToSaveAsPreview = null;
|
||||
|
||||
if(passWordEncodedValue!=null )
|
||||
{
|
||||
|
||||
PageRequest pageRequest = new PageRequest(0, AppUserApiConstant.numberOfPreviousPasswords, Sort.Direction.DESC,"removalDate");
|
||||
|
||||
final List<AppUserPreviewPassword> nLastUsedPasswords = this.appUserPreviewPasswordRepository.findByUserId(user.getId(),pageRequest);
|
||||
|
||||
for(AppUserPreviewPassword aPreviewPassword : nLastUsedPasswords)
|
||||
{
|
||||
|
||||
if(aPreviewPassword.getPassword().equals(passWordEncodedValue)){
|
||||
|
||||
throw new PasswordPreviouslyUsedException();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
currentPasswordToSaveAsPreview = new AppUserPreviewPassword(user);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return currentPasswordToSaveAsPreview ;
|
||||
|
||||
}
|
||||
|
||||
private Set<Role> assembleSetOfRoles(final String[] rolesArray) {
|
||||
|
||||
final Set<Role> allRoles = new HashSet<Role>();
|
||||
|
||||
Reference in New Issue
Block a user