Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ private Constants() {

public static final String PARAMETER_ELEMENT_TYPE_NAME = "parameter";
public static final String PROPERTY_ELEMENT_TYPE_NAME = "property";
public static final String SECURE_EXTENSION_DESCRIPTOR_ID = "__mta.secure";
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package org.cloudfoundry.multiapps.mta.builders;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.cloudfoundry.multiapps.common.ContentException;
import org.cloudfoundry.multiapps.mta.Constants;
import org.cloudfoundry.multiapps.mta.Messages;
import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor;
import org.cloudfoundry.multiapps.mta.model.Descriptor;
Expand All @@ -16,6 +19,8 @@ public class ExtensionDescriptorChainBuilder {

private final boolean isStrict;

private ExtensionDescriptor secureExtensionDescriptor;

public ExtensionDescriptorChainBuilder() {
this(true);
}
Expand All @@ -24,8 +29,11 @@ public ExtensionDescriptorChainBuilder(boolean isStrict) {
this.isStrict = isStrict;
}

public List<ExtensionDescriptor> build(DeploymentDescriptor deploymentDescriptor, List<ExtensionDescriptor> extensionDescriptors)
throws ContentException {
private boolean isSecureDescriptor(ExtensionDescriptor extensionDescriptor) {
return extensionDescriptor.getId().equals(Constants.SECURE_EXTENSION_DESCRIPTOR_ID);
}

public List<ExtensionDescriptor> build(DeploymentDescriptor deploymentDescriptor, List<ExtensionDescriptor> extensionDescriptors) throws ContentException {
Map<String, ExtensionDescriptor> extensionDescriptorsPerParent = getExtensionDescriptorsPerParent(extensionDescriptors);
return build(deploymentDescriptor, extensionDescriptorsPerParent);
}
Expand All @@ -34,37 +42,68 @@ private List<ExtensionDescriptor> build(DeploymentDescriptor deploymentDescripto
Map<String, ExtensionDescriptor> extensionDescriptorsPerParent) {
List<ExtensionDescriptor> chain = new ArrayList<>();
Descriptor currentDescriptor = deploymentDescriptor;
ExtensionDescriptor secureDescriptor = null;

while (currentDescriptor != null) {
ExtensionDescriptor nextDescriptor = extensionDescriptorsPerParent.remove(currentDescriptor.getId());

if(nextDescriptor != null && isSecureDescriptor(nextDescriptor)) {
secureDescriptor = nextDescriptor;
continue;
}

CollectionUtils.addIgnoreNull(chain, nextDescriptor);
currentDescriptor = nextDescriptor;
}

CollectionUtils.addIgnoreNull(chain, secureDescriptor);

if(secureDescriptor == null && this.secureExtensionDescriptor != null) {
CollectionUtils.addIgnoreNull(chain, this.secureExtensionDescriptor);
}

if (!extensionDescriptorsPerParent.isEmpty() && isStrict) {
throw new ContentException(Messages.CANNOT_BUILD_EXTENSION_DESCRIPTOR_CHAIN_BECAUSE_DESCRIPTORS_0_HAVE_AN_UNKNOWN_PARENT,
String.join(",", Descriptor.getIds(extensionDescriptorsPerParent.values())));
}

return chain;
}

private Map<String, ExtensionDescriptor> getExtensionDescriptorsPerParent(List<ExtensionDescriptor> extensionDescriptors) {
Map<String, List<ExtensionDescriptor>> extensionDescriptorsPerParent = extensionDescriptors.stream()
.collect(Collectors.groupingBy(ExtensionDescriptor::getParentId));
Map<String, List<ExtensionDescriptor>> extensionDescriptorsPerParent = extensionDescriptors.stream().collect(Collectors.groupingBy(ExtensionDescriptor::getParentId));
validateSingleExtensionDescriptorPerParent(extensionDescriptorsPerParent);
return prune(extensionDescriptorsPerParent);
}

private Map<String, ExtensionDescriptor> prune(Map<String, List<ExtensionDescriptor>> extensionDescriptorsPerParent) {
validateSingleExtensionDescriptorPerParent(extensionDescriptorsPerParent);
return extensionDescriptorsPerParent.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()
.get(0)));
.collect(Collectors.toMap(Map.Entry::getKey, entry -> {
List<ExtensionDescriptor> localList = entry.getValue();

for(ExtensionDescriptor extensionDescriptor : localList) {
if(extensionDescriptor.getId().equals(Constants.SECURE_EXTENSION_DESCRIPTOR_ID)) {
this.secureExtensionDescriptor = extensionDescriptor;
}
}

for(ExtensionDescriptor extensionDescriptor : localList) {
Comment on lines +84 to +91
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still do not get why this whole change in collect method is needed.
Isn't it enough just to ignore the secure extension descriptor here?

if(!extensionDescriptor.getId().equals(Constants.SECURE_EXTENSION_DESCRIPTOR_ID)) {
return extensionDescriptor;
}
}

return localList.get(0);
}));
}

private void validateSingleExtensionDescriptorPerParent(Map<String, List<ExtensionDescriptor>> extensionDescriptorsPerParent) {
for (Map.Entry<String, List<ExtensionDescriptor>> extensionDescriptorsForParent : extensionDescriptorsPerParent.entrySet()) {
String parent = extensionDescriptorsForParent.getKey();
List<ExtensionDescriptor> extensionDescriptors = extensionDescriptorsForParent.getValue();
if (extensionDescriptors.size() > 1 && isStrict) {
long nonSecureCountOfExtensionDescriptors = extensionDescriptors.stream().filter(descriptor -> !descriptor.getId().equals(Constants.SECURE_EXTENSION_DESCRIPTOR_ID)).count();
if (nonSecureCountOfExtensionDescriptors > 1 && isStrict) {
throw new ContentException(Messages.MULTIPLE_EXTENSION_DESCRIPTORS_EXTEND_THE_PARENT_0, parent);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.cloudfoundry.multiapps.common.util.yaml.YamlElement;
import org.cloudfoundry.multiapps.mta.parsers.v3.ExtensionHookParser;

public class ExtensionHook extends VersionedEntity implements VisitableElement, NamedElement {
public class ExtensionHook extends VersionedEntity implements VisitableElement, NamedElement, ParametersContainer {

// Required by Jackson.
protected ExtensionHook() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package org.cloudfoundry.multiapps.mta.builders;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.cloudfoundry.multiapps.common.ContentException;
import org.cloudfoundry.multiapps.mta.Constants;
import org.cloudfoundry.multiapps.mta.Messages;
import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor;
import org.cloudfoundry.multiapps.mta.model.ExtensionDescriptor;
Expand Down Expand Up @@ -102,6 +106,86 @@ void testLaxBuildWithMultipleDescriptorsExtendingTheSameParent() {
assertEquals(Collections.emptyList(), extensionDescriptorChain);
}

@Test
void testBuildWithNormalAndSecureExtensionDescriptorsWhereSecureIsLastInTheChain() {
DeploymentDescriptor deploymentDescriptor = buildDeploymentDescriptor(FOO_ID);
ExtensionDescriptor normalExtensionDescriptor = buildExtensionDescriptor(BAR_ID, FOO_ID);
ExtensionDescriptor secureExtensionDescriptor = buildSecureExtensionDescriptor(FOO_ID);

List<ExtensionDescriptor> extensionDescriptors = List.of(secureExtensionDescriptor, normalExtensionDescriptor);

ExtensionDescriptorChainBuilder extensionDescriptorChainBuilder = new ExtensionDescriptorChainBuilder();
List<ExtensionDescriptor> extensionDescriptorChain = extensionDescriptorChainBuilder.build(deploymentDescriptor, extensionDescriptors);

assertEquals(List.of(normalExtensionDescriptor, secureExtensionDescriptor), extensionDescriptorChain);
}

@Test
void testBuildWithOnlySecureExtensionDescriptor() {
DeploymentDescriptor deploymentDescriptor = buildDeploymentDescriptor(FOO_ID);
ExtensionDescriptor secureExtensionDescriptor = buildSecureExtensionDescriptor(FOO_ID);

List<ExtensionDescriptor> extensionDescriptors = Collections.singletonList(secureExtensionDescriptor);

ExtensionDescriptorChainBuilder extensionDescriptorChainBuilder = new ExtensionDescriptorChainBuilder();
List<ExtensionDescriptor> extensionDescriptorChain = extensionDescriptorChainBuilder.build(deploymentDescriptor, extensionDescriptors);

assertEquals(Collections.singletonList(secureExtensionDescriptor), extensionDescriptorChain);
}

@Test
void testBuildWhenSecureExtensionDescriptorIsExtendedStrictMode() {
DeploymentDescriptor deploymentDescriptor = buildDeploymentDescriptor(FOO_ID);
ExtensionDescriptor firstExtensionDescriptor = buildExtensionDescriptor(BAR_ID, FOO_ID);
ExtensionDescriptor secureExtensionDescriptor = buildSecureExtensionDescriptor(BAR_ID);
ExtensionDescriptor extensionDescriptorAfterSecureOne = buildExtensionDescriptor(QUX_ID, Constants.SECURE_EXTENSION_DESCRIPTOR_ID);

List<ExtensionDescriptor> extensionDescriptors = List.of(extensionDescriptorAfterSecureOne, firstExtensionDescriptor, secureExtensionDescriptor);

ExtensionDescriptorChainBuilder extensionDescriptorChainBuilder = new ExtensionDescriptorChainBuilder(true);

ContentException contentException = assertThrows(ContentException.class, () -> extensionDescriptorChainBuilder.build(deploymentDescriptor, extensionDescriptors));

String expectedMessage = MessageFormat.format(
Messages.CANNOT_BUILD_EXTENSION_DESCRIPTOR_CHAIN_BECAUSE_DESCRIPTORS_0_HAVE_AN_UNKNOWN_PARENT,
extensionDescriptorAfterSecureOne.getId()
);
assertEquals(expectedMessage, contentException.getMessage());
}

@Test
void testBuildWhenSecureExtensionDescriptorIsExtendedNonStrictMode() {
DeploymentDescriptor deploymentDescriptor = buildDeploymentDescriptor(FOO_ID);
ExtensionDescriptor firstExtensionDescriptor = buildExtensionDescriptor(BAR_ID, FOO_ID);
ExtensionDescriptor secureExtensionDescriptor = buildSecureExtensionDescriptor(BAR_ID);
ExtensionDescriptor extensionDescriptorAfterSecureOne = buildExtensionDescriptor(QUX_ID, Constants.SECURE_EXTENSION_DESCRIPTOR_ID);

List<ExtensionDescriptor> extensionDescriptors = List.of(extensionDescriptorAfterSecureOne, secureExtensionDescriptor, firstExtensionDescriptor);

ExtensionDescriptorChainBuilder extensionDescriptorChainBuilder = new ExtensionDescriptorChainBuilder(false);
List<ExtensionDescriptor> extensionDescriptorChain = extensionDescriptorChainBuilder.build(deploymentDescriptor, extensionDescriptors);

assertEquals(List.of(firstExtensionDescriptor, secureExtensionDescriptor), extensionDescriptorChain);
}

@Test
void testBuildWhenTwoSecureExtensionDescriptorsWhereOnlyTheLastOneGetsAppended() {
DeploymentDescriptor deploymentDescriptor = buildDeploymentDescriptor(FOO_ID);
ExtensionDescriptor firstExtensionDescriptor = buildExtensionDescriptor(BAR_ID, FOO_ID);
ExtensionDescriptor firstSecureExtensionDescriptor = buildSecureExtensionDescriptor(FOO_ID);
ExtensionDescriptor secondSecureExtensionDescriptor = buildSecureExtensionDescriptor(FOO_ID);

List<ExtensionDescriptor> extensionDescriptors = List.of(firstSecureExtensionDescriptor, firstExtensionDescriptor, secondSecureExtensionDescriptor);

ExtensionDescriptorChainBuilder extensionDescriptorChainBuilder = new ExtensionDescriptorChainBuilder();
List<ExtensionDescriptor> extensionDescriptorChain = extensionDescriptorChainBuilder.build(deploymentDescriptor, extensionDescriptors);

assertEquals(2, extensionDescriptorChain.size());
assertEquals(firstExtensionDescriptor, extensionDescriptorChain.get(0));
assertEquals(Constants.SECURE_EXTENSION_DESCRIPTOR_ID, extensionDescriptorChain.get(1).getId());
assertSame(secondSecureExtensionDescriptor, extensionDescriptorChain.get(1));
}

private DeploymentDescriptor buildDeploymentDescriptor(String id) {
return DeploymentDescriptor.createV2()
.setId(id);
Expand All @@ -113,4 +197,10 @@ private ExtensionDescriptor buildExtensionDescriptor(String id, String parentId)
.setId(id);
}

private ExtensionDescriptor buildSecureExtensionDescriptor(String parentId) {
return ExtensionDescriptor.createV2()
.setParentId(parentId)
.setId(Constants.SECURE_EXTENSION_DESCRIPTOR_ID);
}

}
Loading