From f232c8c260cb67b483d688909e239bf7715cc1d3 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Tue, 06 Aug 2024 15:00:24 +0000
Subject: [PATCH] [#204] ADD LDAP Relax Rules Control (#362)
---
opendj-doc-generated-ref/src/main/docbkx/admin-guide/index.xml | 8 ++
opendj-core/src/main/java/org/forgerock/opendj/ldap/controls/RelaxRulesControl.java | 43 ++++++++++
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java | 15 +++
opendj-doc-generated-ref/src/main/docbkx/admin-guide/appendix-controls.xml | 15 +++
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Utils.java | 17 +---
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java | 15 +++
opendj-server-legacy/src/test/java/org/openidentityplatform/opendj/RelaxRulesTestCase.java | 83 ++++++++++++++++++++
7 files changed, 180 insertions(+), 16 deletions(-)
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/controls/RelaxRulesControl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/controls/RelaxRulesControl.java
new file mode 100644
index 0000000..ecbdcd0
--- /dev/null
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/controls/RelaxRulesControl.java
@@ -0,0 +1,43 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyright [year] [name of copyright owner]".
+ *
+ * Copyright 2024 3A Systems,LLC.
+ */
+package org.forgerock.opendj.ldap.controls;
+
+import org.forgerock.opendj.ldap.ByteString;
+
+public class RelaxRulesControl implements Control{
+
+ public final static String OID="1.3.6.1.4.1.4203.666.5.12";
+
+ @Override
+ public String getOID() {
+ return OID;
+ }
+
+ @Override
+ public ByteString getValue() {
+ return null;
+ }
+
+ @Override
+ public boolean hasValue() {
+ return false;
+ }
+
+ @Override
+ public boolean isCritical() {
+ return true;
+ }
+}
diff --git a/opendj-doc-generated-ref/src/main/docbkx/admin-guide/appendix-controls.xml b/opendj-doc-generated-ref/src/main/docbkx/admin-guide/appendix-controls.xml
index 1f16425..5e88d56 100644
--- a/opendj-doc-generated-ref/src/main/docbkx/admin-guide/appendix-controls.xml
+++ b/opendj-doc-generated-ref/src/main/docbkx/admin-guide/appendix-controls.xml
@@ -21,6 +21,7 @@
! CCPL HEADER END
!
! Copyright 2011 ForgeRock AS
+ ! Portions copyright 2024 3A Systems,LLC.
!
-->
<appendix xml:id='appendix-controls'
@@ -445,5 +446,19 @@
Browsing of Search Results</link></para>
</listitem>
</varlistentry>
+
+ <varlistentry xml:id="relax-rules-control">
+ <term>The LDAP Relax Rules Control</term>
+ <listitem>
+ <indexterm>
+ <primary>LDAP controls</primary>
+ <secondary>Relax Rules Control</secondary>
+ </indexterm>
+ <para>Object Identifier: 1.3.6.1.4.1.4203.666.5.12</para>
+ <para>Internet-Draft: <link
+ xlink:href='https://tools.ietf.org/html/draft-zeilenga-ldap-relax-03'
+ >ddraft-zeilenga-ldap-relax-03 - The LDAP Relax Rules Control</link></para>
+ </listitem>
+ </varlistentry>
</variablelist>
</appendix>
diff --git a/opendj-doc-generated-ref/src/main/docbkx/admin-guide/index.xml b/opendj-doc-generated-ref/src/main/docbkx/admin-guide/index.xml
index cc280db..e2647ee 100644
--- a/opendj-doc-generated-ref/src/main/docbkx/admin-guide/index.xml
+++ b/opendj-doc-generated-ref/src/main/docbkx/admin-guide/index.xml
@@ -21,6 +21,7 @@
! CCPL HEADER END
!
! Copyright 2011-2014 ForgeRock AS
+ ! Portions copyright 2024 3A Systems,LLC.
!
-->
<book xml:id='admin-guide'
@@ -40,8 +41,15 @@
<year>2011-2014</year>
<holder>ForgeRock AS</holder>
</copyright>
+ <copyright>
+ <year>2024- </year>
+ <holder>Open Identity Platform Community</holder>
+ </copyright>
<authorgroup>
<author>
+ <personname><firstname>Valery </firstname><surname>Kharseko</surname></personname>
+ </author>
+ <author>
<personname><firstname>Mark </firstname><surname>Craig</surname></personname>
</author>
<author>
diff --git a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Utils.java b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Utils.java
index 54651f3..b56505a 100644
--- a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Utils.java
+++ b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Utils.java
@@ -13,6 +13,7 @@
*
* Copyright 2006-2010 Sun Microsystems, Inc.
* Portions copyright 2014-2016 ForgeRock AS.
+ * Portions copyright 2022-2024 3A Systems,LLC.
*/
package com.forgerock.opendj.ldap.tools;
@@ -58,19 +59,7 @@
import org.forgerock.opendj.ldap.Filter;
import org.forgerock.opendj.ldap.LdapException;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.controls.AssertionRequestControl;
-import org.forgerock.opendj.ldap.controls.AuthorizationIdentityRequestControl;
-import org.forgerock.opendj.ldap.controls.AuthorizationIdentityResponseControl;
-import org.forgerock.opendj.ldap.controls.Control;
-import org.forgerock.opendj.ldap.controls.GenericControl;
-import org.forgerock.opendj.ldap.controls.GetEffectiveRightsRequestControl;
-import org.forgerock.opendj.ldap.controls.PasswordExpiredResponseControl;
-import org.forgerock.opendj.ldap.controls.PasswordExpiringResponseControl;
-import org.forgerock.opendj.ldap.controls.PasswordPolicyErrorType;
-import org.forgerock.opendj.ldap.controls.PasswordPolicyRequestControl;
-import org.forgerock.opendj.ldap.controls.PasswordPolicyResponseControl;
-import org.forgerock.opendj.ldap.controls.PasswordPolicyWarningType;
-import org.forgerock.opendj.ldap.controls.SubtreeDeleteRequestControl;
+import org.forgerock.opendj.ldap.controls.*;
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.requests.Request;
import org.forgerock.opendj.ldap.responses.BindResult;
@@ -379,6 +368,8 @@
case "effectiverights":
case "geteffectiverights":
return GetEffectiveRightsRequestControl.OID;
+ case "relaxrules":
+ return RelaxRulesControl.OID;
case "noop":
case "no-op":
case "subentries":
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
index 6ae0629..3aa4daa 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -13,6 +13,7 @@
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions copyright 2024 3A Systems,LLC.
*/
package org.opends.server.workflowelement.localbackend;
@@ -37,6 +38,7 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.controls.RelaxRulesControl;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.forgerock.opendj.ldap.schema.ObjectClass;
import org.forgerock.opendj.ldap.schema.Syntax;
@@ -108,7 +110,8 @@
private Map<AttributeType, List<Attribute>> operationalAttributes;
/** The set of user attributes for the entry to add. */
private Map<AttributeType, List<Attribute>> userAttributes;
-
+ /** Indicates whether the request included the RelaxRules request control. */
+ private boolean RelaxRulesControlRequested=false;
/**
* Creates a new operation that may be used to add a new entry in a
* local backend of the Directory Server.
@@ -122,6 +125,10 @@
LocalBackendWorkflowElement.attachLocalOperation (add, this);
}
+ @Override
+ public boolean isSynchronizationOperation() {
+ return super.isSynchronizationOperation()||RelaxRulesControlRequested;
+ }
/**
@@ -406,7 +413,7 @@
// sensitive information to the client.
try
{
- if (!getAccessControlHandler().isAllowed(this))
+ if (!getAccessControlHandler().isAllowed(this) || (RelaxRulesControlRequested && !clientConnection.hasPrivilege(Privilege.BYPASS_ACL, this)))
{
setResultCodeAndMessageNoInfoDisclosure(entryDN,
ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
@@ -957,6 +964,10 @@
// We don't need to do anything here because it's already handled
// in LocalBackendAddOperation.handlePasswordPolicy().
}
+ else if (RelaxRulesControl.OID.equals(oid))
+ {
+ RelaxRulesControlRequested = true;
+ }
else if (c.isCritical() && !backend.supportsControl(oid))
{
throw newDirectoryException(entryDN, ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
index 963ea88..070c528 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -13,6 +13,7 @@
*
* Copyright 2008-2011 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions copyright 2024 3A Systems,LLC.
*/
package org.opends.server.workflowelement.localbackend;
@@ -33,6 +34,7 @@
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.RDN;
import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.controls.RelaxRulesControl;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.forgerock.opendj.ldap.schema.MatchingRule;
import org.forgerock.opendj.ldap.schema.ObjectClass;
@@ -123,6 +125,8 @@
private boolean permissiveModify;
/** Indicates whether the request included the password policy request control. */
private boolean pwPolicyControlRequested;
+ /** Indicates whether the request included the RelaxRules request control. */
+ private boolean RelaxRulesControlRequested=false;
/** The post-read request control, if present. */
private LDAPPostReadRequestControl postReadRequest;
/** The pre-read request control, if present. */
@@ -163,6 +167,11 @@
LocalBackendWorkflowElement.attachLocalOperation (modify, this);
}
+ @Override
+ public boolean isSynchronizationOperation() {
+ return super.isSynchronizationOperation()||RelaxRulesControlRequested;
+ }
+
/**
* Returns whether authentication for this user is managed locally
* or via Pass-Through Authentication.
@@ -527,7 +536,7 @@
{
try
{
- if (!getAccessControlHandler().isAllowed(this))
+ if (!getAccessControlHandler().isAllowed(this) || (RelaxRulesControlRequested && !clientConnection.hasPrivilege(Privilege.BYPASS_ACL, this)))
{
setResultCodeAndMessageNoInfoDisclosure(modifiedEntry,
ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
@@ -684,6 +693,10 @@
{
pwPolicyControlRequested = true;
}
+ else if (RelaxRulesControl.OID.equals(oid))
+ {
+ RelaxRulesControlRequested = true;
+ }
else if (c.isCritical() && !backend.supportsControl(oid))
{
throw newDirectoryException(currentEntry, ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
diff --git a/opendj-server-legacy/src/test/java/org/openidentityplatform/opendj/RelaxRulesTestCase.java b/opendj-server-legacy/src/test/java/org/openidentityplatform/opendj/RelaxRulesTestCase.java
new file mode 100644
index 0000000..703b85d
--- /dev/null
+++ b/opendj-server-legacy/src/test/java/org/openidentityplatform/opendj/RelaxRulesTestCase.java
@@ -0,0 +1,83 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyright [year] [name of copyright owner]".
+ *
+ * Copyright 2024 3A Systems, LLC.
+ */
+package org.openidentityplatform.opendj;
+
+
+import org.forgerock.opendj.adapter.server3x.Adapters;
+import org.forgerock.opendj.ldap.*;
+import org.forgerock.opendj.ldap.controls.RelaxRulesControl;
+import org.forgerock.opendj.ldap.requests.ModifyRequest;
+import org.forgerock.opendj.ldap.requests.Requests;
+import org.forgerock.opendj.ldap.responses.Result;
+import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.opends.server.DirectoryServerTestCase;
+import org.opends.server.TestCaseUtils;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Test(sequential = true)
+public class RelaxRulesTestCase extends DirectoryServerTestCase {
+ Connection connection;
+
+ @BeforeClass
+ public void startServer() throws Exception {
+ TestCaseUtils.startServer();
+ TestCaseUtils.initializeTestBackend(true);
+
+ TestCaseUtils.addEntries(
+ "dn: uid=user.2, o=test",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: inetOrgPerson",
+ "objectClass: organizationalPerson",
+ "cn: Aarika Atpco",
+ "sn: user.2",
+ "uid:user.2",
+ "description: This is the description for Aarika Atpco.",
+ "userPassword:: cGFzc3dvcmQ=",
+ "postalAddress: Aarika Atpco$00900 Maple Street$New Orleans, KS 10857",
+ "postalCode: 10857",
+ ""
+ );
+
+ final LDAPConnectionFactory factory =new LDAPConnectionFactory("localhost", TestCaseUtils.getServerLdapPort());
+ connection = factory.getConnection();
+ connection.bind("cn=Directory Manager", "password".toCharArray());
+ assertThat(connection.isValid()).isTrue();
+ }
+
+ @Test
+ public void test() throws LdapException {
+ final ModifyRequest changeRequest =
+ Requests.newModifyRequest("uid=user.2, o=test")
+ .addControl(new RelaxRulesControl())
+ .addModification(ModificationType.REPLACE, "pwdChangedTime", "20211203224637.000Z");
+
+ final Result result = connection.modify(changeRequest);
+ assertThat(result.getDiagnosticMessage()).isEmpty();
+ assertThat(result.getMatchedDN()).isEmpty();
+
+ //Verifies that entry has been correctly modified.
+ final SearchResultEntry srEntry =
+ connection.searchSingleEntry(Requests.newSearchRequest(
+ "uid=user.2, o=test", SearchScope.BASE_OBJECT, "(uid=user.2)").addAttribute("+"));
+ assertThat(srEntry.getAttribute("pwdChangedTime").firstValueAsString()).isEqualTo(
+ "20211203224637.000Z");
+ }
+}
--
Gitblit v1.10.0