FINERACT-2081: External service credential values masked
This commit is contained in:
committed by
Adam Saghy
parent
07ea81e399
commit
b4b2ef3701
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.core.service;
|
||||
|
||||
public final class StringUtil {
|
||||
|
||||
private StringUtil() {}
|
||||
|
||||
public static String maskValue(String value) {
|
||||
return maskValue(value, 4);
|
||||
}
|
||||
|
||||
public static String maskValue(String value, Integer unmaskedLength) {
|
||||
if (value.length() <= unmaskedLength) {
|
||||
return "****";
|
||||
}
|
||||
return value.substring(0, 1) + "*".repeat(value.length() - 1 - unmaskedLength) + value.substring(value.length() - unmaskedLength);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -233,7 +233,6 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
|
||||
if (command.isChangeInPasswordParameterNamed(passwordParamName, this.password, platformPasswordEncoder, getId())) {
|
||||
final String passwordEncodedValue = command.passwordValueOfParameterNamed(passwordParamName, platformPasswordEncoder,
|
||||
getId());
|
||||
actualChanges.put(passwordEncodedParamName, passwordEncodedValue);
|
||||
updatePassword(passwordEncodedValue);
|
||||
}
|
||||
}
|
||||
@@ -241,7 +240,6 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
|
||||
if (command.hasParameter(passwordEncodedParamName)) {
|
||||
if (command.isChangeInStringParameterNamed(passwordEncodedParamName, this.password)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(passwordEncodedParamName);
|
||||
actualChanges.put(passwordEncodedParamName, newValue);
|
||||
updatePassword(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -18,10 +18,12 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.configuration.data;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.apache.fineract.infrastructure.core.jersey.serializer.MaskedValueSerializer;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@@ -31,6 +33,7 @@ public class ExternalServicesPropertiesData implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String name;
|
||||
@JsonSerialize(using = MaskedValueSerializer.class)
|
||||
private String value;
|
||||
|
||||
}
|
||||
|
||||
+13
-3
@@ -20,13 +20,16 @@ package org.apache.fineract.infrastructure.configuration.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.MessageGatewayConfigurationData;
|
||||
import org.apache.fineract.infrastructure.configuration.data.ExternalServicesPropertiesData;
|
||||
import org.apache.fineract.infrastructure.configuration.data.S3CredentialsData;
|
||||
import org.apache.fineract.infrastructure.configuration.data.SMTPCredentialsData;
|
||||
import org.apache.fineract.infrastructure.configuration.exception.ExternalServiceConfigurationNotFoundException;
|
||||
import org.apache.fineract.infrastructure.core.service.StringUtil;
|
||||
import org.apache.fineract.infrastructure.gcm.domain.NotificationConfigurationData;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -99,14 +102,21 @@ public class ExternalServicesPropertiesReadPlatformServiceImpl implements Extern
|
||||
|
||||
private static final class ExternalServiceMapper implements RowMapper<ExternalServicesPropertiesData> {
|
||||
|
||||
List<String> secretAttributes;
|
||||
|
||||
ExternalServiceMapper() {
|
||||
secretAttributes = new ArrayList<>();
|
||||
secretAttributes.add("password");
|
||||
secretAttributes.add("server_key");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalServicesPropertiesData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
|
||||
// TODO Auto-generated method stub
|
||||
final String name = rs.getString("name");
|
||||
String value = rs.getString("value");
|
||||
// Masking the password as we should not send the password back
|
||||
if (name != null && "password".equalsIgnoreCase(name)) {
|
||||
value = "XXXX";
|
||||
if (name != null && secretAttributes.contains(name)) {
|
||||
value = StringUtil.maskValue(value);
|
||||
}
|
||||
return new ExternalServicesPropertiesData().setName(name).setValue(value);
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.core.jersey.serializer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import java.io.IOException;
|
||||
import org.apache.fineract.infrastructure.core.service.StringUtil;
|
||||
|
||||
public class MaskedValueSerializer extends JsonSerializer<String> {
|
||||
|
||||
@Override
|
||||
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
if (value == null || value.isBlank()) {
|
||||
gen.writeString(value);
|
||||
return;
|
||||
}
|
||||
|
||||
String masked = StringUtil.maskValue(value);
|
||||
gen.writeString(masked);
|
||||
}
|
||||
|
||||
}
|
||||
-2
@@ -197,8 +197,6 @@ final class UsersApiResourceSwagger {
|
||||
|
||||
@Schema(example = "Test")
|
||||
public String firstname;
|
||||
@Schema(example = "abc3326b1bb376351c7baeb4175f5e0504e33aadf6a158474a6d71de1befae51")
|
||||
public String passwordEncoded;
|
||||
}
|
||||
|
||||
@Schema(example = "1")
|
||||
|
||||
+24
-1
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.apache.fineract.integrationtests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
import io.restassured.http.ContentType;
|
||||
@@ -83,7 +85,6 @@ public class ExternalServicesConfigurationTest {
|
||||
}
|
||||
|
||||
// Checking for SMTP:
|
||||
|
||||
configName = "username";
|
||||
externalServicesConfig = ExternalServicesConfigurationHelper.getExternalServicesConfigurationByServiceName(requestSpec,
|
||||
responseSpec, "SMTP");
|
||||
@@ -111,6 +112,28 @@ public class ExternalServicesConfigurationTest {
|
||||
|
||||
}
|
||||
|
||||
// Checking for Notifications:
|
||||
configName = "server_key";
|
||||
externalServicesConfig = ExternalServicesConfigurationHelper.getExternalServicesConfigurationByServiceName(requestSpec,
|
||||
responseSpec, "NOTIFICATION");
|
||||
Assertions.assertNotNull(externalServicesConfig);
|
||||
|
||||
for (Integer configIndex = 0; configIndex < externalServicesConfig.size(); configIndex++) {
|
||||
String name = (String) externalServicesConfig.get(configIndex).get("name");
|
||||
String value = null;
|
||||
if (name.equals(configName)) {
|
||||
value = (String) externalServicesConfig.get(configIndex).get("value");
|
||||
if (value == null) {
|
||||
value = "testnull";
|
||||
}
|
||||
LOG.info("{} : {}", name, value);
|
||||
assertTrue(hasMoreThanThreeStars(value));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasMoreThanThreeStars(String input) {
|
||||
return input != null && input.matches("(.*\\*.*){4,}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user