| New file |
| | |
| | | /* |
| | | * 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 2026 3A Systems, LLC. |
| | | */ |
| | | package com.forgerock.opendj.ldap.tools; |
| | | |
| | | import static com.forgerock.opendj.ldap.tools.ToolsMessages.ERR_TOOL_INVALID_CONTROL_STRING; |
| | | import static com.forgerock.opendj.util.OperatingSystem.isWindows; |
| | | import static org.fest.assertions.Assertions.assertThat; |
| | | import static org.testng.Assert.fail; |
| | | |
| | | import java.io.File; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.nio.file.Files; |
| | | import java.util.List; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.controls.Control; |
| | | import org.forgerock.testng.ForgeRockTestCase; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import com.forgerock.opendj.cli.CommonArguments; |
| | | import com.forgerock.opendj.cli.StringArgument; |
| | | |
| | | /** Tests the parsing of the {@code -J/--control} argument by {@link Utils#readControls(StringArgument)}. */ |
| | | @Test |
| | | public final class ControlArgumentTestCase extends ForgeRockTestCase { |
| | | |
| | | @DataProvider |
| | | public Object[][] validControls() { |
| | | return new Object[][] { |
| | | { "1.2.3.4", "1.2.3.4", false, null }, |
| | | { "1.2.3.4:true", "1.2.3.4", true, null }, |
| | | { "1.2.3.4:FALSE:value", "1.2.3.4", false, "value" }, |
| | | { "1.2.3.4:true:", "1.2.3.4", true, "" }, |
| | | { "pwpolicy:true", "1.3.6.1.4.1.42.2.27.8.5.1", true, null }, |
| | | // Everything after the second colon is the value, colons included. |
| | | { "2.16.840.1.113730.3.4.18:true:dn:uid=bjensen,ou=People,dc=example,dc=com", |
| | | "2.16.840.1.113730.3.4.18", true, "dn:uid=bjensen,ou=People,dc=example,dc=com" }, |
| | | { "2.16.840.1.113730.3.4.18:true:u:bjensen", "2.16.840.1.113730.3.4.18", true, "u:bjensen" }, |
| | | { "1.2.3.4:false:urn:example:value", "1.2.3.4", false, "urn:example:value" }, |
| | | { "1.2.3.4:false:ldap://host:1389/dc=example", "1.2.3.4", false, "ldap://host:1389/dc=example" }, |
| | | // The base64 form decodes to a value that can itself hold colons. |
| | | { "1.2.3.4:true::" + base64("dn:uid=bjensen"), "1.2.3.4", true, "dn:uid=bjensen" }, |
| | | { "1.2.3.4:true::", "1.2.3.4", true, "" }, |
| | | }; |
| | | } |
| | | |
| | | @Test(dataProvider = "validControls") |
| | | public void testValidControl(final String argument, final String oid, final boolean critical, |
| | | final String value) throws Exception { |
| | | final Control control = readSingleControl(argument); |
| | | assertThat(control.getOID()).isEqualTo(oid); |
| | | assertThat(control.isCritical()).isEqualTo(critical); |
| | | if (value == null) { |
| | | assertThat(control.hasValue()).isFalse(); |
| | | } else { |
| | | assertThat(control.hasValue()).isTrue(); |
| | | assertThat(control.getValue().toString()).isEqualTo(value); |
| | | } |
| | | } |
| | | |
| | | @Test |
| | | public void testValueReadFromFileWhosePathHoldsAColon() throws Exception { |
| | | // On Windows the drive letter puts a colon in every absolute path; elsewhere the file name carries one. |
| | | final File dir = Files.createTempDirectory("control-value").toFile(); |
| | | final File file = new File(dir, isWindows() ? "control-value.ber" : "control:value.ber"); |
| | | try { |
| | | final byte[] bytes = { 0x04, 0x03, 'a', ':', 'b' }; |
| | | Files.write(file.toPath(), bytes); |
| | | |
| | | final Control control = readSingleControl("1.2.3.4:true:<" + file.getAbsolutePath()); |
| | | assertThat(control.getOID()).isEqualTo("1.2.3.4"); |
| | | assertThat(control.isCritical()).isTrue(); |
| | | assertThat(control.getValue()).isEqualTo(ByteString.wrap(bytes)); |
| | | } finally { |
| | | file.delete(); |
| | | dir.delete(); |
| | | } |
| | | } |
| | | |
| | | @DataProvider |
| | | public Object[][] invalidControls() { |
| | | final String missingFile = new File(System.getProperty("java.io.tmpdir"), "no-such-dir-1156/value.ber") |
| | | .getAbsolutePath(); |
| | | return new Object[][] { |
| | | { "1.2.3.4:invalidcriticality" }, |
| | | { "1.2.3.4:invalidcriticality:value" }, |
| | | { "1.2.3.4:true:<" + missingFile }, |
| | | { "1.2.3.4:true::not*base64" }, |
| | | }; |
| | | } |
| | | |
| | | @Test(dataProvider = "invalidControls") |
| | | public void testInvalidControlIsReportedAsAnInvalidControlString(final String argument) throws Exception { |
| | | try { |
| | | readControls(argument); |
| | | fail("Expected the control '" + argument + "' to be rejected"); |
| | | } catch (final LDAPToolException e) { |
| | | assertThat(e.getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | assertThat(e.getMessage()).isEqualTo(ERR_TOOL_INVALID_CONTROL_STRING.get(argument).toString()); |
| | | } |
| | | } |
| | | |
| | | private static Control readSingleControl(final String argument) throws Exception { |
| | | final List<Control> controls = readControls(argument); |
| | | assertThat(controls).hasSize(1); |
| | | return controls.get(0); |
| | | } |
| | | |
| | | private static List<Control> readControls(final String argument) throws Exception { |
| | | final StringArgument controlArg = CommonArguments.controlArgument(); |
| | | controlArg.addValue(argument); |
| | | controlArg.setPresent(true); |
| | | return Utils.readControls(controlArg); |
| | | } |
| | | |
| | | private static String base64(final String value) { |
| | | return ByteString.valueOfBytes(value.getBytes(StandardCharsets.UTF_8)).toBase64String(); |
| | | } |
| | | } |