Skip to content

Commit

Permalink
fix: Return placeholder instead of encrypted passwords in REST APIs (#…
Browse files Browse the repository at this point in the history
…4893)

fix: Return placeholder instead of encrypted passwords in web ui

Signed-off-by: Nicola Timeus <[email protected]>
  • Loading branch information
nicolatimeus authored and pierantoniomerlino committed Oct 13, 2023
1 parent 97889fe commit 8d75084
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ Import-Package: javax.annotation.security;version="1.2.0",
org.osgi.service.component;version="1.3.0",
org.osgi.service.useradmin;version="1.1.0";resolution:=optional,
org.slf4j;version="1.7.25"
Export-Package: org.eclipse.kura.rest.configuration.api;version="1.0.0"
Export-Package: org.eclipse.kura.rest.configuration.api;version="1.1.0"
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others
* Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -361,7 +361,7 @@ public ComponentConfigurationList listComponentConfigurations() {
throw DefaultExceptionHandler.toWebApplicationException(e);
}

return DTOUtil.toComponentConfigurationList(ccs, this.cryptoService, false);
return DTOUtil.toComponentConfigurationList(ccs, this.cryptoService, false).replacePasswordsWithPlaceholder();

}

Expand Down Expand Up @@ -398,7 +398,8 @@ public ComponentConfigurationList listComponentConfigurations(final PidSet pids)
}
});

return DTOUtil.toComponentConfigurationList(configs, this.cryptoService, false);
return DTOUtil.toComponentConfigurationList(configs, this.cryptoService, false)
.replacePasswordsWithPlaceholder();
}

/**
Expand Down Expand Up @@ -562,4 +563,5 @@ public Response rollbackSnapshot(final SnapshotId id) {

return Response.ok().build();
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others
* Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -12,12 +12,15 @@
*******************************************************************************/
package org.eclipse.kura.rest.configuration.api;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;

import javax.ws.rs.core.Response.Status;

import org.eclipse.kura.configuration.metatype.OCD;
import org.eclipse.kura.configuration.metatype.Scalar;
import org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;

public class ComponentConfigurationDTO implements Validable {
Expand Down Expand Up @@ -45,6 +48,43 @@ public Map<String, PropertyDTO> getProperties() {
return this.properties;
}

public ComponentConfigurationDTO replacePasswordsWithPlaceholder() {

if (properties == null) {
return this;
}

final Map<String, PropertyDTO> result = new HashMap<>(this.properties);

for (final Entry<String, PropertyDTO> e : result.entrySet()) {
e.setValue(replacePasswordsWithPlaceholder(e.getValue()));
}

return new ComponentConfigurationDTO(pid, definition, result);
}

public PropertyDTO replacePasswordsWithPlaceholder(final PropertyDTO property) {

if (property == null || property.getType() != Scalar.PASSWORD) {
return property;
}

if (property.getValue() instanceof String[]) {
final String[] asStringArray = (String[]) property.getValue();
final String[] result = new String[asStringArray.length];

for (int i = 0; i < asStringArray.length; i++) {
if (asStringArray[i] != null) {
result[i] = "placeholder";
}
}

return new PropertyDTO(result, Scalar.PASSWORD);
} else {
return new PropertyDTO("placeholder", Scalar.PASSWORD);
}
}

@Override
public void validate() {
FailureHandler.requireParameter(this.pid, "pid");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others
* Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -13,6 +13,7 @@
package org.eclipse.kura.rest.configuration.api;

import java.util.List;
import java.util.stream.Collectors;

public class ComponentConfigurationList implements Validable {

Expand All @@ -30,4 +31,14 @@ public List<ComponentConfigurationDTO> getConfigs() {
public void validate() {
FailureHandler.requireParameter(this.configs, "configs");
}

public ComponentConfigurationList replacePasswordsWithPlaceholder() {
if (configs == null) {
return this;
}

return new ComponentConfigurationList(
configs.stream().map(ComponentConfigurationDTO::replacePasswordsWithPlaceholder)
.collect(Collectors.toList()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Import-Package: com.google.gson;version="2.7.0",
org.eclipse.kura.internal.wire.asset;version="[1.0,2.0)",
org.eclipse.kura.marshalling;version="[1.0,2.0)",
org.eclipse.kura.request.handler.jaxrs;version="[1.0,2.0)",
org.eclipse.kura.rest.configuration.api;version="[1.0,2.0)",
org.eclipse.kura.rest.configuration.api;version="[1.1,2.0)",
org.eclipse.kura.util.service;version="[1.0,2.0)",
org.eclipse.kura.wire;version="[2.0,3.0)",
org.eclipse.kura.wire.graph;version="[1.0,2.0)",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2022 Eurotech and/or its affiliates and others
* Copyright (c) 2023 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -362,7 +362,7 @@ public ComponentConfigurationList getWireConfigsByPid(final PidSet pidSet) {
}
}

return DTOUtil.toComponentConfigurationList(result, cryptoService, true);
return DTOUtil.toComponentConfigurationList(result, cryptoService, false).replacePasswordsWithPlaceholder();

} catch (final Exception e) {
throw DefaultExceptionHandler.toWebApplicationException(e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others
* Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -80,7 +80,7 @@
@RunWith(Parameterized.class)
public class ConfigurationRestServiceTest extends AbstractRequestHandlerTest {

private char[] EncryptedPassword;
private char[] encryptedPassword;

@Test
public void shouldSupportGetSnapshots() throws KuraException {
Expand Down Expand Up @@ -270,16 +270,45 @@ public void testGetLongProperty() throws KuraException {
}

@Test
public void testGetPasswordProperty() throws KuraException {
this.EncryptedPassword = this.cryptoService.encryptAes("foobar".toCharArray());
public void testReturnPlaceholderInsteadOfEncryptedPassword() throws KuraException {
givenEncryptedPassword("foobar");
givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.PASSWORD,
new Password(this.EncryptedPassword));
new Password(this.encryptedPassword));

whenRequestIsPerformed(new MethodSpec("GET"), "/configurableComponents/configurations");

thenRequestSucceeds();
thenTestPropertyTypeIs(Json.value("PASSWORD"));
thenTestPropertyValueIs(Json.value(new String(this.EncryptedPassword)));
thenTestPropertyValueIs(Json.value("placeholder"));
}

@Test
public void testReturnNoValueForMissingPasswordProperty() throws KuraException {
givenEncryptedPassword("foobar");
givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.PASSWORD,
null);

whenRequestIsPerformed(new MethodSpec("GET"), "/configurableComponents/configurations");

thenRequestSucceeds();
thenTestPropertyIsMissing();
}

@Test
public void testGetSnapshotReturnsUnencryptedPassword() throws KuraException {
givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.PASSWORD,
new Password("foobar".toCharArray()));

whenRequestIsPerformed(new MethodSpec("POST"), "/snapshots/byId",
"{\"id\":1}");

thenRequestSucceeds();
thenTestPropertyTypeIs(Json.value("PASSWORD"));
thenTestPropertyValueIs(Json.value("foobar"));
}

private void givenEncryptedPassword(final String password) throws KuraException {
this.encryptedPassword = this.cryptoService.encryptAes(password.toCharArray());
}

@Test
Expand Down Expand Up @@ -394,16 +423,16 @@ public void testGetLongArrayProperty() throws KuraException {
@Test
public void testGetPasswordArrayProperty() throws KuraException {

this.EncryptedPassword = this.cryptoService.encryptAes("foobar".toCharArray());
givenEncryptedPassword("foobar");

givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.PASSWORD,
new Password[] { new Password(this.EncryptedPassword) });
new Password[] { new Password(this.encryptedPassword) });

whenRequestIsPerformed(new MethodSpec("GET"), "/configurableComponents/configurations");

thenRequestSucceeds();
thenTestPropertyTypeIs(Json.value("PASSWORD"));
thenTestPropertyValueIs(Json.array(new String(this.EncryptedPassword)));
thenTestPropertyValueIs(Json.array("placeholder"));
}

@Test
Expand Down Expand Up @@ -1036,7 +1065,7 @@ public void testADOption() throws KuraException {

@Test
public void testGetConfigurationByPid() throws KuraException {
this.EncryptedPassword = this.cryptoService.encryptAes("foobar".toCharArray());
givenEncryptedPassword("foobar");
givenConfigurations(configurationBuilder("foo") //
.withDefinition( //
ocdBuilder("foo") //
Expand All @@ -1046,7 +1075,7 @@ public void testGetConfigurationByPid() throws KuraException {
.build()) //
.build()) //
.withConfigurationProperties(
singletonMap("testProp", new Password[] { new Password(this.EncryptedPassword) }))
singletonMap("testProp", new Password[] { new Password(this.encryptedPassword) }))
.build());

whenRequestIsPerformed(new MethodSpec("POST"), "/configurableComponents/configurations/byPid",
Expand All @@ -1058,14 +1087,14 @@ public void testGetConfigurationByPid() throws KuraException {
+ "{\"label\":\"pass\",\"value\":\"baz\"}],\"id\":\"fooAdName\",\"type\":\"PASSWORD\","
+ "\"cardinality\":0,\"isRequired\":false}],\"id\":\"foo\"},"
+ "\"properties\":{\"testProp\":{\"value\":[\""
+ new String(this.EncryptedPassword)
+ "placeholder"
+ "\"],\"type\":\"PASSWORD\"}}}"),
self().field("configs").arrayItem(0));
}

@Test
public void testGetConfigurationByPidDefault() throws KuraException {
this.EncryptedPassword = this.cryptoService.encryptAes("foobar".toCharArray());
givenEncryptedPassword("foobar");
givenConfigurations(configurationBuilder("foo") //
.withDefinition( //
ocdBuilder("foo") //
Expand All @@ -1076,7 +1105,7 @@ public void testGetConfigurationByPidDefault() throws KuraException {
.build()) //
.build()) //
.withConfigurationProperties(
singletonMap("testProp", new Password[] { new Password(this.EncryptedPassword) }))
singletonMap("testProp", new Password[] { new Password(this.encryptedPassword) }))
.build());

whenRequestIsPerformed(new MethodSpec("POST"), "/configurableComponents/configurations/byPid/_default",
Expand All @@ -1088,7 +1117,7 @@ public void testGetConfigurationByPidDefault() throws KuraException {
+ "{\"label\":\"pass\",\"value\":\"baz\"}],\"id\":\"fooAdName\",\"type\":\"STRING\","
+ "\"cardinality\":0,\"defaultValue\":\"default\",\"isRequired\":false}]"
+ ",\"id\":\"foo\"},\"properties\":{\"testProp\":{\"value\":[\""
+ new String(this.EncryptedPassword)
+ new String(this.encryptedPassword)
+ "\"],\"type\":\"PASSWORD\"}}}"),
self().field("configs").arrayItem(0));
}
Expand Down Expand Up @@ -1405,6 +1434,9 @@ private void givenConfigurations(final ComponentConfiguration... configurations)
final String pid = i.getArgument(0, String.class);
return byPid.get(pid);
});

Mockito.when(configurationService.getSnapshot(Mockito.anyLong()))
.thenReturn(byPid.values().stream().collect(Collectors.toList()));
}

private void givenATestConfigurationPropertyWithAdTypeAndValue(final Scalar type, final Object value)
Expand Down

0 comments on commit 8d75084

Please sign in to comment.