Skip to content

Commit

Permalink
Improve ldapsearch/ldapmodify --proxyAs handling
Browse files Browse the repository at this point in the history
Updated the ldapsearch and ldapmodify command-line tools to provide
better validation for the value of the --proxyAs argument.  The
tools will now reject attempts to use the argument with a value that
doesn't start with either "dn:" or "u:", and they will also reject
attempts to use a value that starts with "dn:" but is not followed
by a valid LDAP DN.
  • Loading branch information
dirmgr committed Nov 30, 2023
1 parent eb22dc8 commit 8b21d0a
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 2 deletions.
9 changes: 9 additions & 0 deletions docs/release-notes.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ <h3>Version 6.0.11</h3>
<br><br>
</li>

<li>
Updated the ldapsearch and ldapmodify command-line tools to provide better
validation for the value of the --proxyAs argument. The tools will now reject
attempts to use the argument with a value that doesn't start with either "dn:" or
"u:", and they will also reject attempts to use a value that starts with "dn:"
but is not followed by a valid LDAP DN.
<br><br>
</li>

<li>
Updated the Filter methods for creating substring filters to better support empty
components. In LDAP filters, filters are transmitted using a binary encoding,
Expand Down
12 changes: 12 additions & 0 deletions messages/unboundid-ldapsdk-tools.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1533,6 +1533,12 @@ ERR_LDAPMODIFY_ROUTE_TO_BACKEND_SET_INVALID_FORMAT=Value ''{0}'' provided for \
argument ''{1}'' is invalid. The value must contain the ID of the \
entry-balancing request processor followed by a colon and the ID of a \
desired backend set to use for that entry-balancing request processor.
ERR_LDAPMODIFY_PROXY_AS_DN_NOT_DN=The value of the {0} argument is not valid \
because ''{1}'' cannot be parsed as a valid LDAP DN.
ERR_LDAPMODIFY_PROXY_AS_VALUE_MISSING_PREFIX=The value of the {0} argument is \
not valid because it does not start with either ''dn:'' (to indicate that \
the following value is an LDAP DN) or ''u:'' (to indicate that the \
following value is a username).
ERR_LDAPMODIFY_CANNOT_CREATE_CONNECTION_POOL=An error occurred while \
attempting to create a connection pool to communicate with the directory \
server: {0}
Expand Down Expand Up @@ -2341,6 +2347,12 @@ ERR_LDAPSEARCH_ROUTE_TO_BACKEND_SET_INVALID_FORMAT=Value ''{0}'' provided for \
ERR_LDAPSEARCH_RENAME_ATTRIBUTE_MISMATCH=The --renameAttributeFrom argument \
must be provided the same number of times as the --renameAttributeTo \
argument.
ERR_LDAPSEARCH_PROXY_AS_DN_NOT_DN=The value of the {0} argument is not valid \
because ''{1}'' cannot be parsed as a valid LDAP DN.
ERR_LDAPSEARCH_PROXY_AS_VALUE_MISSING_PREFIX=The value of the {0} argument is \
not valid because it does not start with either ''dn:'' (to indicate that \
the following value is an LDAP DN) or ''u:'' (to indicate that the \
following value is a username).
ERR_LDAPSEARCH_MOVE_SUBTREE_MISMATCH=The --moveSubtreeFrom argument must be \
provided the same number of times as the --moveSubtreeTo argument.
ERR_LDAPSEARCH_OUTPUT_FORMAT_NOT_SUPPORTED_WITH_URLS=The ''{0}'' output \
Expand Down
24 changes: 24 additions & 0 deletions src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPModify.java
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,30 @@ public void doExtendedNonLDAPArgumentValidation()
rpID, bsIDs));
}
}


// If the --proxyAs argument was provided, then make sure its value is
// properly formatted.
if (proxyAs.isPresent())
{
final String proxyAsValue = proxyAs.getValue();
final String lowerProxyAsValue = StaticUtils.toLowerCase(proxyAsValue);
if (lowerProxyAsValue.startsWith("dn:"))
{
final String dnString = proxyAsValue.substring(3);
if (! DN.isValidDN(dnString))
{
throw new ArgumentException(ERR_LDAPMODIFY_PROXY_AS_DN_NOT_DN.get(
proxyAs.getIdentifierString(), dnString));
}
}
else if (! lowerProxyAsValue.startsWith("u:"))
{
throw new ArgumentException(
ERR_LDAPMODIFY_PROXY_AS_VALUE_MISSING_PREFIX.get(
proxyAs.getIdentifierString()));
}
}
}


Expand Down
48 changes: 46 additions & 2 deletions src/com/unboundid/ldap/sdk/unboundidds/tools/LDAPSearch.java
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,8 @@ public void addNonLDAPArguments(@NotNull final ArgumentParser parser)
INFO_PLACEHOLDER_AUTHZID.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_PROXY_AS.get());
proxyAs.addLongIdentifier("proxy-as", true);
proxyAs.addLongIdentifier("proxyV2As", true);
proxyAs.addLongIdentifier("proxy-v2-as", true);
proxyAs.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(proxyAs);

Expand Down Expand Up @@ -2199,6 +2201,30 @@ else if (derefStr.equals("find"))
}


// If the --proxyAs argument was provided, then make sure its value is
// properly formatted.
if (proxyAs.isPresent())
{
final String proxyAsValue = proxyAs.getValue();
final String lowerProxyAsValue = StaticUtils.toLowerCase(proxyAsValue);
if (lowerProxyAsValue.startsWith("dn:"))
{
final String dnString = proxyAsValue.substring(3);
if (! DN.isValidDN(dnString))
{
throw new ArgumentException(ERR_LDAPSEARCH_PROXY_AS_DN_NOT_DN.get(
proxyAs.getIdentifierString(), dnString));
}
}
else if (! lowerProxyAsValue.startsWith("u:"))
{
throw new ArgumentException(
ERR_LDAPSEARCH_PROXY_AS_VALUE_MISSING_PREFIX.get(
proxyAs.getIdentifierString()));
}
}


// See if any entry transformations need to be applied.
final ArrayList<EntryTransformation> transformations = new ArrayList<>(5);
if (excludeAttribute.isPresent())
Expand Down Expand Up @@ -3442,8 +3468,26 @@ else if (valueStr.equals("without-non-deleted-entries"))

if (proxyAs.isPresent())
{
controls.add(new ProxiedAuthorizationV2RequestControl(
proxyAs.getValue()));
final String proxyAsValue = proxyAs.getValue();
final String lowerProxyAsValue = StaticUtils.toLowerCase(proxyAsValue);
if (lowerProxyAsValue.startsWith("dn:"))
{
final String dnString = proxyAsValue.substring(3);
if (! DN.isValidDN(dnString))
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_LDAPSEARCH_PROXY_AS_DN_NOT_DN.get(
proxyAs.getIdentifierString(), dnString));
}
}
else if (! lowerProxyAsValue.startsWith("u:"))
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_LDAPSEARCH_PROXY_AS_VALUE_MISSING_PREFIX.get(
proxyAs.getIdentifierString()));
}

controls.add(new ProxiedAuthorizationV2RequestControl(proxyAsValue));
}

if (proxyV1As.isPresent())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3449,4 +3449,65 @@ public void testInvalidAccessLogFieldControls()
"--ldifFile", ldifFile.getAbsolutePath()),
ResultCode.PARAM_ERROR);
}



/**
* Tests to ensure that the tool rejects attempts to use the --proxyAs
* argument with invalid values.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test()
public void testInvalidProxyAsValues()
throws Exception
{
final InMemoryDirectoryServer ds = getTestDS(true, true);

final File ldifFile = createTempFile(
"dn: dc=example,dc=com",
"changetype: modify",
"replace: description",
"description: foo");

assertEquals(
LDAPModify.main((InputStream) null, null, null,
"--hostname", "localhost",
"--port", String.valueOf(ds.getListenPort()),
"--proxyAs", "missing-prefix",
"--ldifFile", ldifFile.getAbsolutePath()),
ResultCode.PARAM_ERROR);

assertEquals(
LDAPModify.main((InputStream) null, null, null,
"--hostname", "localhost",
"--port", String.valueOf(ds.getListenPort()),
"--proxyAs", "i:invalid-prefix",
"--ldifFile", ldifFile.getAbsolutePath()),
ResultCode.PARAM_ERROR);

assertEquals(
LDAPModify.main((InputStream) null, null, null,
"--hostname", "localhost",
"--port", String.valueOf(ds.getListenPort()),
"--proxyAs", "dn:not-a-dn",
"--ldifFile", ldifFile.getAbsolutePath()),
ResultCode.PARAM_ERROR);

assertEquals(
LDAPModify.main((InputStream) null, null, null,
"--hostname", "localhost",
"--port", String.valueOf(ds.getListenPort()),
"--proxyAs", "dn:uid=test.user,ou=People,dc=example,dc=com",
"--ldifFile", ldifFile.getAbsolutePath()),
ResultCode.SUCCESS);

assertEquals(
LDAPModify.main((InputStream) null, null, null,
"--hostname", "localhost",
"--port", String.valueOf(ds.getListenPort()),
"--proxyAs", "u:test.user",
"--ldifFile", ldifFile.getAbsolutePath()),
ResultCode.SUCCESS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2770,4 +2770,67 @@ public void testInvalidAccessLogFieldControls()
"(objectClass=*)"),
ResultCode.PARAM_ERROR);
}



/**
* Tests to ensure that the tool rejects attempts to use the --proxyAs
* argument with invalid values.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test()
public void testInvalidProxyAsValues()
throws Exception
{
assertEquals(
LDAPSearch.main(NULL_OUTPUT_STREAM, NULL_OUTPUT_STREAM,
"--hostname", "localhost",
"--port", String.valueOf(ds.getListenPort()),
"--baseDN", "",
"--scope", "base",
"--proxyAs", "missing-prefix",
"(objectClass=*)"),
ResultCode.PARAM_ERROR);

assertEquals(
LDAPSearch.main(NULL_OUTPUT_STREAM, NULL_OUTPUT_STREAM,
"--hostname", "localhost",
"--port", String.valueOf(ds.getListenPort()),
"--baseDN", "",
"--scope", "base",
"--proxyAs", "i:invalid-prefix",
"(objectClass=*)"),
ResultCode.PARAM_ERROR);

assertEquals(
LDAPSearch.main(NULL_OUTPUT_STREAM, NULL_OUTPUT_STREAM,
"--hostname", "localhost",
"--port", String.valueOf(ds.getListenPort()),
"--baseDN", "",
"--scope", "base",
"--proxyAs", "dn:not-a-dn",
"(objectClass=*)"),
ResultCode.PARAM_ERROR);

assertEquals(
LDAPSearch.main(NULL_OUTPUT_STREAM, NULL_OUTPUT_STREAM,
"--hostname", "localhost",
"--port", String.valueOf(ds.getListenPort()),
"--baseDN", "",
"--scope", "base",
"--proxyAs", "dn:uid=aaron.adams,ou=People,dc=example,dc=com",
"(objectClass=*)"),
ResultCode.SUCCESS);

assertEquals(
LDAPSearch.main(NULL_OUTPUT_STREAM, NULL_OUTPUT_STREAM,
"--hostname", "localhost",
"--port", String.valueOf(ds.getListenPort()),
"--baseDN", "",
"--scope", "base",
"--proxyAs", "u:aaron.adams",
"(objectClass=*)"),
ResultCode.SUCCESS);
}
}

0 comments on commit 8b21d0a

Please sign in to comment.