Skip to content

Commit

Permalink
Fix PATCH with nested fields
Browse files Browse the repository at this point in the history
This fixes an issue where PATCH requests with add operation
and no path field containing nested fields (with '.') where
not correctly applied.
  • Loading branch information
luca committed Jun 18, 2024
1 parent 371487f commit f4fbab6
Showing 1 changed file with 223 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.DoubleNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
Expand All @@ -47,9 +48,11 @@

import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

import static com.unboundid.scim2.common.utils.StaticUtils.toList;

Expand Down Expand Up @@ -220,7 +223,7 @@ public void apply(@NotNull final ObjectNode node) throws ScimException
}
else
{
JsonUtils.addValue(path, node, value);
applyAdd(node);
}

addMissingSchemaUrns(node);
Expand Down Expand Up @@ -414,6 +417,90 @@ private void applyAddWithValueFilter(
existingResource.replace(attributeName, attribute);
}

private void applyAdd(final ObjectNode node) throws ScimException
{
Path path = null;
if (getPath() == null)
{
if (value.getNodeType() == JsonNodeType.OBJECT)
{
boolean containsDot = false;

final List<String> keys = new ArrayList<>();
final Iterator<String> iterator = value.fieldNames();
iterator.forEachRemaining(e -> keys.add(e));

for (final String key : keys)
{
if (key.contains("."))
{
containsDot = true;
break;
}
}

if (containsDot)
{
final ObjectNode removedValues = (ObjectNode) value.deepCopy();
final List<Path> dotPaths = keys.stream().filter(key -> key.contains("."))
.map(key -> {
try
{
return Path.fromString(key);
}
catch (final BadRequestException e)
{
return Path.root();
}
}).collect(Collectors.toList());

for (final Path dotPath : dotPaths)
{
JsonNode dotPathJsonNode = value.get(dotPath.toString());
if (SchemaUtils.isUrn(dotPath.toString()))
{
if (dotPathJsonNode.getNodeType() != JsonNodeType.OBJECT &&
dotPathJsonNode.getNodeType() != JsonNodeType.ARRAY)
{
JsonUtils.addValue(dotPath, node, dotPathJsonNode);

removedValues.remove(dotPath.toString());
}
}
else
{

JsonUtils.addValue(dotPath, node, dotPathJsonNode);

removedValues.remove(dotPath.toString());
}
}

path = Path.root();
JsonUtils.addValue(path, node, removedValues);
}
else
{
path = Path.root();

JsonUtils.addValue(path, node, value);
}
}
else
{
path = Path.root();

JsonUtils.addValue(path, node, value);
}
}
else
{
path = getPath();

JsonUtils.addValue(path, node, value);
}
}

/**
* Indicates whether the provided object is equal to this add operation.
*
Expand Down Expand Up @@ -627,11 +714,130 @@ public <T> List<T> getValues(@NotNull final Class<T> cls)
@Override
public void apply(@NotNull final ObjectNode node) throws ScimException
{
Path path = (getPath() == null) ? Path.root() : getPath();
JsonUtils.replaceValue(path, node, value);
applyReplace(node);
addMissingSchemaUrns(node);
}

private void applyReplace(final ObjectNode node) throws ScimException
{
Path path = null;
List<Path> existingPaths = Collections.emptyList();
List<Path> nonExistingPaths = Collections.emptyList();
if (getPath() == null)
{
if (value.getNodeType() == JsonNodeType.OBJECT)
{
boolean containsDot = false;

final List<String> keys = new ArrayList<>();
final Iterator<String> iterator = value.fieldNames();
iterator.forEachRemaining(e -> keys.add(e));

for (final String key : keys)
{
if (key.contains("."))
{
containsDot = true;
break;
}
}

if (containsDot)
{
existingPaths = keys.stream().filter(key ->
{
try
{
return JsonUtils.pathExists(Path.fromString(key), node);
}
catch (final BadRequestException e)
{
return false;
}
catch (final ScimException e)
{
return false;
}
}).map(key ->
{
try
{
return Path.fromString(key);
}
catch (final BadRequestException e)
{
return Path.root();
}
}).collect(Collectors.toList());

nonExistingPaths = keys.stream().filter(key ->
{
try
{
return !JsonUtils.pathExists(Path.fromString(key), node);
}
catch (final BadRequestException e)
{
return false;
}
catch (final ScimException e)
{
return false;
}
}).map(key ->
{
try
{
return Path.fromString(key);
}
catch (final BadRequestException e)
{
return Path.root();
}
}).collect(Collectors.toList());

if (existingPaths.size() <= 0)
{
path = Path.root();

JsonUtils.replaceValue(path, node, value);
}
else
{
for (final Path existingPath : existingPaths)
{
JsonUtils.replaceValue(existingPath, node, value.get(existingPath.toString()));
}

for (final Path nonExistingPath : nonExistingPaths)
{
JsonUtils.replaceValue(nonExistingPath, node,
value.get(nonExistingPath.toString()));
}
}
}
else
{
path = Path.root();

JsonUtils.replaceValue(path, node, value);
}
}
else
{
path = Path.root();

JsonUtils.replaceValue(path, node, value);
}
}
else
{
path = getPath();

JsonUtils.replaceValue(path, node, value);
}
}

/**
* Indicates whether the provided object is equal to this replace operation.
*
Expand Down Expand Up @@ -855,15 +1061,26 @@ else if(getPath().getSchemaUrn() != null)
private void addSchemaUrnIfMissing(@NotNull final ArrayNode schemas,
@NotNull final String schemaUrn)
{
for(JsonNode node : schemas)
final String enterpriseUserUri = "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User";
for (final JsonNode node : schemas)
{
if(node.isTextual() && node.textValue().equalsIgnoreCase(schemaUrn))
if (node.isTextual()
&& (node.textValue().equalsIgnoreCase(schemaUrn)
|| node.textValue().toUpperCase().contains(enterpriseUserUri.toUpperCase())))
{
return;
}
}

schemas.add(schemaUrn);
if (schemaUrn.toUpperCase().contains(enterpriseUserUri.toUpperCase())
&& schemaUrn.length() > enterpriseUserUri.length())
{
schemas.add(enterpriseUserUri);
}
else
{
schemas.add(schemaUrn);
}
}

/**
Expand Down

0 comments on commit f4fbab6

Please sign in to comment.