Skip to content

Commit 5789560

Browse files
authored
Enabling the use of secrets during a deployment
* Enabling the use of secrets during a deployment LMCROSSITXSADEPLOY-2301
1 parent 51c836a commit 5789560

4 files changed

Lines changed: 167 additions & 27 deletions

File tree

multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ private Constants() {
77

88
public static final String PARAMETER_ELEMENT_TYPE_NAME = "parameter";
99
public static final String PROPERTY_ELEMENT_TYPE_NAME = "property";
10+
public static final String SECURE_EXTENSION_DESCRIPTOR_ID = "__mta.secure";
1011
}
Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
package org.cloudfoundry.multiapps.mta.builders;
22

3-
import java.util.ArrayList;
4-
import java.util.List;
5-
import java.util.Map;
6-
import java.util.stream.Collectors;
7-
83
import org.apache.commons.collections4.CollectionUtils;
94
import org.cloudfoundry.multiapps.common.ContentException;
5+
import org.cloudfoundry.multiapps.mta.Constants;
106
import org.cloudfoundry.multiapps.mta.Messages;
117
import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor;
128
import org.cloudfoundry.multiapps.mta.model.Descriptor;
139
import org.cloudfoundry.multiapps.mta.model.ExtensionDescriptor;
1410

11+
import java.util.ArrayList;
12+
import java.util.LinkedHashMap;
13+
import java.util.List;
14+
import java.util.Map;
15+
import java.util.stream.Collectors;
16+
1517
public class ExtensionDescriptorChainBuilder {
1618

1719
private final boolean isStrict;
1820

21+
private ExtensionDescriptor secureExtensionDescriptor;
22+
1923
public ExtensionDescriptorChainBuilder() {
2024
this(true);
2125
}
@@ -24,8 +28,14 @@ public ExtensionDescriptorChainBuilder(boolean isStrict) {
2428
this.isStrict = isStrict;
2529
}
2630

31+
private boolean isSecureDescriptor(ExtensionDescriptor extensionDescriptor) {
32+
return extensionDescriptor.getId()
33+
.equals(Constants.SECURE_EXTENSION_DESCRIPTOR_ID);
34+
}
35+
2736
public List<ExtensionDescriptor> build(DeploymentDescriptor deploymentDescriptor, List<ExtensionDescriptor> extensionDescriptors)
2837
throws ContentException {
38+
saveSecureExtensionDescriptor(extensionDescriptors);
2939
Map<String, ExtensionDescriptor> extensionDescriptorsPerParent = getExtensionDescriptorsPerParent(extensionDescriptors);
3040
return build(deploymentDescriptor, extensionDescriptorsPerParent);
3141
}
@@ -34,40 +44,70 @@ private List<ExtensionDescriptor> build(DeploymentDescriptor deploymentDescripto
3444
Map<String, ExtensionDescriptor> extensionDescriptorsPerParent) {
3545
List<ExtensionDescriptor> chain = new ArrayList<>();
3646
Descriptor currentDescriptor = deploymentDescriptor;
47+
3748
while (currentDescriptor != null) {
3849
ExtensionDescriptor nextDescriptor = extensionDescriptorsPerParent.remove(currentDescriptor.getId());
3950
CollectionUtils.addIgnoreNull(chain, nextDescriptor);
4051
currentDescriptor = nextDescriptor;
4152
}
53+
54+
CollectionUtils.addIgnoreNull(chain, this.secureExtensionDescriptor);
55+
4256
if (!extensionDescriptorsPerParent.isEmpty() && isStrict) {
4357
throw new ContentException(Messages.CANNOT_BUILD_EXTENSION_DESCRIPTOR_CHAIN_BECAUSE_DESCRIPTORS_0_HAVE_AN_UNKNOWN_PARENT,
4458
String.join(",", Descriptor.getIds(extensionDescriptorsPerParent.values())));
4559
}
60+
4661
return chain;
4762
}
4863

4964
private Map<String, ExtensionDescriptor> getExtensionDescriptorsPerParent(List<ExtensionDescriptor> extensionDescriptors) {
5065
Map<String, List<ExtensionDescriptor>> extensionDescriptorsPerParent = extensionDescriptors.stream()
51-
.collect(Collectors.groupingBy(ExtensionDescriptor::getParentId));
66+
.collect(Collectors.groupingBy(
67+
ExtensionDescriptor::getParentId));
68+
validateSingleExtensionDescriptorPerParent(extensionDescriptorsPerParent);
5269
return prune(extensionDescriptorsPerParent);
5370
}
5471

5572
private Map<String, ExtensionDescriptor> prune(Map<String, List<ExtensionDescriptor>> extensionDescriptorsPerParent) {
56-
validateSingleExtensionDescriptorPerParent(extensionDescriptorsPerParent);
57-
return extensionDescriptorsPerParent.entrySet()
58-
.stream()
59-
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()
60-
.get(0)));
73+
Map<String, ExtensionDescriptor> resultMap = new LinkedHashMap<>();
74+
75+
for (Map.Entry<String, List<ExtensionDescriptor>> entry : extensionDescriptorsPerParent.entrySet()) {
76+
for (ExtensionDescriptor currentExtensionDescriptorForParent : entry.getValue()) {
77+
if (!isSecureDescriptor(currentExtensionDescriptorForParent)) {
78+
resultMap.put(entry.getKey(), currentExtensionDescriptorForParent);
79+
break;
80+
}
81+
}
82+
}
83+
return resultMap;
6184
}
6285

6386
private void validateSingleExtensionDescriptorPerParent(Map<String, List<ExtensionDescriptor>> extensionDescriptorsPerParent) {
6487
for (Map.Entry<String, List<ExtensionDescriptor>> extensionDescriptorsForParent : extensionDescriptorsPerParent.entrySet()) {
6588
String parent = extensionDescriptorsForParent.getKey();
6689
List<ExtensionDescriptor> extensionDescriptors = extensionDescriptorsForParent.getValue();
67-
if (extensionDescriptors.size() > 1 && isStrict) {
90+
long nonSecureCountOfExtensionDescriptors = extensionDescriptors.stream()
91+
.filter(descriptor -> !descriptor.getId()
92+
.equals(
93+
Constants.SECURE_EXTENSION_DESCRIPTOR_ID))
94+
.count();
95+
if (nonSecureCountOfExtensionDescriptors > 1 && isStrict) {
6896
throw new ContentException(Messages.MULTIPLE_EXTENSION_DESCRIPTORS_EXTEND_THE_PARENT_0, parent);
6997
}
7098
}
7199
}
72100

73-
}
101+
private void saveSecureExtensionDescriptor(List<ExtensionDescriptor> extensionDescriptors) {
102+
ExtensionDescriptor lastSecureExtensionDescriptor = null;
103+
104+
for (ExtensionDescriptor extensionDescriptor : extensionDescriptors) {
105+
if (isSecureDescriptor(extensionDescriptor)) {
106+
lastSecureExtensionDescriptor = extensionDescriptor;
107+
}
108+
}
109+
110+
this.secureExtensionDescriptor = lastSecureExtensionDescriptor;
111+
}
112+
113+
}

multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/model/ExtensionHook.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package org.cloudfoundry.multiapps.mta.model;
22

3-
import java.util.Collections;
4-
import java.util.List;
5-
import java.util.Map;
6-
73
import org.apache.commons.lang3.ObjectUtils;
84
import org.cloudfoundry.multiapps.common.util.yaml.YamlElement;
95
import org.cloudfoundry.multiapps.mta.parsers.v3.ExtensionHookParser;
106

11-
public class ExtensionHook extends VersionedEntity implements VisitableElement, NamedElement {
7+
import java.util.Collections;
8+
import java.util.List;
9+
import java.util.Map;
10+
11+
public class ExtensionHook extends VersionedEntity implements VisitableElement, NamedElement, ParametersContainer {
1212

1313
// Required by Jackson.
1414
protected ExtensionHook() {

multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/builders/ExtensionDescriptorChainBuilderTest.java

Lines changed: 108 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
package org.cloudfoundry.multiapps.mta.builders;
22

3-
import static org.junit.jupiter.api.Assertions.assertEquals;
4-
import static org.junit.jupiter.api.Assertions.assertThrows;
3+
import org.cloudfoundry.multiapps.common.ContentException;
4+
import org.cloudfoundry.multiapps.mta.Constants;
5+
import org.cloudfoundry.multiapps.mta.Messages;
6+
import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor;
7+
import org.cloudfoundry.multiapps.mta.model.ExtensionDescriptor;
8+
import org.junit.jupiter.api.Test;
59

610
import java.text.MessageFormat;
711
import java.util.Arrays;
812
import java.util.Collections;
913
import java.util.List;
1014

11-
import org.cloudfoundry.multiapps.common.ContentException;
12-
import org.cloudfoundry.multiapps.mta.Messages;
13-
import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor;
14-
import org.cloudfoundry.multiapps.mta.model.ExtensionDescriptor;
15-
import org.junit.jupiter.api.Test;
15+
import static org.junit.jupiter.api.Assertions.assertEquals;
16+
import static org.junit.jupiter.api.Assertions.assertSame;
17+
import static org.junit.jupiter.api.Assertions.assertThrows;
1618

1719
class ExtensionDescriptorChainBuilderTest {
1820

@@ -50,8 +52,9 @@ void testBuildWithDescriptorWithUnknownParent() {
5052
ContentException contentException = assertThrows(ContentException.class,
5153
() -> extensionDescriptorChainBuilder.build(deploymentDescriptor,
5254
extensionDescriptors));
53-
String expectedMessage = MessageFormat.format(Messages.CANNOT_BUILD_EXTENSION_DESCRIPTOR_CHAIN_BECAUSE_DESCRIPTORS_0_HAVE_AN_UNKNOWN_PARENT,
54-
extensionDescriptor2.getId());
55+
String expectedMessage = MessageFormat.format(
56+
Messages.CANNOT_BUILD_EXTENSION_DESCRIPTOR_CHAIN_BECAUSE_DESCRIPTORS_0_HAVE_AN_UNKNOWN_PARENT,
57+
extensionDescriptor2.getId());
5558

5659
assertEquals(expectedMessage, contentException.getMessage());
5760
}
@@ -102,6 +105,96 @@ void testLaxBuildWithMultipleDescriptorsExtendingTheSameParent() {
102105
assertEquals(Collections.emptyList(), extensionDescriptorChain);
103106
}
104107

108+
@Test
109+
void testBuildWithNormalAndSecureExtensionDescriptorsWhereSecureIsLastInTheChain() {
110+
DeploymentDescriptor deploymentDescriptor = buildDeploymentDescriptor(FOO_ID);
111+
ExtensionDescriptor normalExtensionDescriptor = buildExtensionDescriptor(BAR_ID, FOO_ID);
112+
ExtensionDescriptor secureExtensionDescriptor = buildSecureExtensionDescriptor(FOO_ID);
113+
114+
List<ExtensionDescriptor> extensionDescriptors = List.of(secureExtensionDescriptor, normalExtensionDescriptor);
115+
116+
ExtensionDescriptorChainBuilder extensionDescriptorChainBuilder = new ExtensionDescriptorChainBuilder();
117+
List<ExtensionDescriptor> extensionDescriptorChain = extensionDescriptorChainBuilder.build(deploymentDescriptor,
118+
extensionDescriptors);
119+
120+
assertEquals(List.of(normalExtensionDescriptor, secureExtensionDescriptor), extensionDescriptorChain);
121+
}
122+
123+
@Test
124+
void testBuildWithOnlySecureExtensionDescriptor() {
125+
DeploymentDescriptor deploymentDescriptor = buildDeploymentDescriptor(FOO_ID);
126+
ExtensionDescriptor secureExtensionDescriptor = buildSecureExtensionDescriptor(FOO_ID);
127+
128+
List<ExtensionDescriptor> extensionDescriptors = Collections.singletonList(secureExtensionDescriptor);
129+
130+
ExtensionDescriptorChainBuilder extensionDescriptorChainBuilder = new ExtensionDescriptorChainBuilder();
131+
List<ExtensionDescriptor> extensionDescriptorChain = extensionDescriptorChainBuilder.build(deploymentDescriptor,
132+
extensionDescriptors);
133+
134+
assertEquals(Collections.singletonList(secureExtensionDescriptor), extensionDescriptorChain);
135+
}
136+
137+
@Test
138+
void testBuildWhenSecureExtensionDescriptorIsExtendedStrictMode() {
139+
DeploymentDescriptor deploymentDescriptor = buildDeploymentDescriptor(FOO_ID);
140+
ExtensionDescriptor firstExtensionDescriptor = buildExtensionDescriptor(BAR_ID, FOO_ID);
141+
ExtensionDescriptor secureExtensionDescriptor = buildSecureExtensionDescriptor(BAR_ID);
142+
ExtensionDescriptor extensionDescriptorAfterSecureOne = buildExtensionDescriptor(QUX_ID, Constants.SECURE_EXTENSION_DESCRIPTOR_ID);
143+
144+
List<ExtensionDescriptor> extensionDescriptors = List.of(extensionDescriptorAfterSecureOne, firstExtensionDescriptor,
145+
secureExtensionDescriptor);
146+
147+
ExtensionDescriptorChainBuilder extensionDescriptorChainBuilder = new ExtensionDescriptorChainBuilder(true);
148+
149+
ContentException contentException = assertThrows(ContentException.class,
150+
() -> extensionDescriptorChainBuilder.build(deploymentDescriptor,
151+
extensionDescriptors));
152+
153+
String expectedMessage = MessageFormat.format(
154+
Messages.CANNOT_BUILD_EXTENSION_DESCRIPTOR_CHAIN_BECAUSE_DESCRIPTORS_0_HAVE_AN_UNKNOWN_PARENT,
155+
extensionDescriptorAfterSecureOne.getId()
156+
);
157+
assertEquals(expectedMessage, contentException.getMessage());
158+
}
159+
160+
@Test
161+
void testBuildWhenSecureExtensionDescriptorIsExtendedNonStrictMode() {
162+
DeploymentDescriptor deploymentDescriptor = buildDeploymentDescriptor(FOO_ID);
163+
ExtensionDescriptor firstExtensionDescriptor = buildExtensionDescriptor(BAR_ID, FOO_ID);
164+
ExtensionDescriptor secureExtensionDescriptor = buildSecureExtensionDescriptor(BAR_ID);
165+
ExtensionDescriptor extensionDescriptorAfterSecureOne = buildExtensionDescriptor(QUX_ID, Constants.SECURE_EXTENSION_DESCRIPTOR_ID);
166+
167+
List<ExtensionDescriptor> extensionDescriptors = List.of(extensionDescriptorAfterSecureOne, secureExtensionDescriptor,
168+
firstExtensionDescriptor);
169+
170+
ExtensionDescriptorChainBuilder extensionDescriptorChainBuilder = new ExtensionDescriptorChainBuilder(false);
171+
List<ExtensionDescriptor> extensionDescriptorChain = extensionDescriptorChainBuilder.build(deploymentDescriptor,
172+
extensionDescriptors);
173+
174+
assertEquals(List.of(firstExtensionDescriptor, secureExtensionDescriptor), extensionDescriptorChain);
175+
}
176+
177+
@Test
178+
void testBuildWhenTwoSecureExtensionDescriptorsWhereOnlyTheLastOneGetsAppended() {
179+
DeploymentDescriptor deploymentDescriptor = buildDeploymentDescriptor(FOO_ID);
180+
ExtensionDescriptor firstExtensionDescriptor = buildExtensionDescriptor(BAR_ID, FOO_ID);
181+
ExtensionDescriptor firstSecureExtensionDescriptor = buildSecureExtensionDescriptor(FOO_ID);
182+
ExtensionDescriptor secondSecureExtensionDescriptor = buildSecureExtensionDescriptor(FOO_ID);
183+
184+
List<ExtensionDescriptor> extensionDescriptors = List.of(firstSecureExtensionDescriptor, firstExtensionDescriptor,
185+
secondSecureExtensionDescriptor);
186+
187+
ExtensionDescriptorChainBuilder extensionDescriptorChainBuilder = new ExtensionDescriptorChainBuilder();
188+
List<ExtensionDescriptor> extensionDescriptorChain = extensionDescriptorChainBuilder.build(deploymentDescriptor,
189+
extensionDescriptors);
190+
191+
assertEquals(2, extensionDescriptorChain.size());
192+
assertEquals(firstExtensionDescriptor, extensionDescriptorChain.get(0));
193+
assertEquals(Constants.SECURE_EXTENSION_DESCRIPTOR_ID, extensionDescriptorChain.get(1)
194+
.getId());
195+
assertSame(secondSecureExtensionDescriptor, extensionDescriptorChain.get(1));
196+
}
197+
105198
private DeploymentDescriptor buildDeploymentDescriptor(String id) {
106199
return DeploymentDescriptor.createV2()
107200
.setId(id);
@@ -113,4 +206,10 @@ private ExtensionDescriptor buildExtensionDescriptor(String id, String parentId)
113206
.setId(id);
114207
}
115208

209+
private ExtensionDescriptor buildSecureExtensionDescriptor(String parentId) {
210+
return ExtensionDescriptor.createV2()
211+
.setParentId(parentId)
212+
.setId(Constants.SECURE_EXTENSION_DESCRIPTOR_ID);
213+
}
214+
116215
}

0 commit comments

Comments
 (0)