/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. * Portions Copyright 2012-2015 ForgeRock AS */ package org.opends.server.protocols.ldap; import static org.opends.server.protocols.internal.InternalClientConnection.*; import static org.opends.server.protocols.internal.Requests.*; import static org.testng.Assert.*; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.net.Socket; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DereferenceAliasesPolicy; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.opendj.ldap.SearchScope; import org.opends.server.TestCaseUtils; import org.opends.server.api.Backend; import org.opends.server.core.DirectoryServer; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.internal.SearchRequest; import org.opends.server.tools.LDAPModify; import org.opends.server.tools.LDAPSearch; import org.opends.server.types.*; import org.opends.server.util.Base64; import org.opends.server.util.StaticUtils; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * This class defines a set of test cases for testing the binary transfer option * functionality across different protocol versions of LDAP. */ public class LDAPBinaryOptionTestCase extends LdapTestCase { /** Exported LDIF file. */ private File ldif; /** LDIFExportConfig used for exporting entries. */ private LDIFExportConfig exportConfig; /** LDIFImportConfig used for importing entries. */ private LDIFImportConfig importConfig; /** Test Backend. */ private Backend<?> backend; /** Constant value of userCertificate attribute. */ private static final String CERT= "MIIB5TCCAU6gAwIBAgIERloIajANBgkqhkiG9" + "w0BAQUFADA3MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRXhhbXBs" + "ZSBDb3JwMREwDwYDVQQDEwhKb2huIERvZTAeFw0wNzA1MjcyMjM4" + "MzRaFw0wNzA4MjUyMjM4MzRaMDcxCzAJBgNVBAYTAlVTMRUwEwYD" + "VQQKEwxFeGFtcGxlIENvcnAxETAPBgNVBAMTCEpvaG4gRG9lMIGfMA" + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCWNZB4qs1UvjYgvGvB" + "9udmiUi4X4DeaSm3o0p8PSwpOFxSqgWdSwKgUugZ1EJVyYoakljDFs" + "J0GVown+dIB24V4ozNs6wa0YotIKTV2AcySQkmzzP3e+OnE9Aa1wlB/" + "PVnh1CFLgk1UOoruLE10bac5HA8QiAmfNMorU26AwFTcwIDAQABMA" + "0GCSqGSIb3DQEBBQUAA4GBAGrzMKNbBRWn+LIfYTfqKYUc258XVbhFri" + "1OV0oF82vyvciYWZzyxLc52EPDsymLmcDh+CdWxy3bVkjdMg1WEtMGr" + "1GsxOVi/vWe+kT4tPhinnB4Fowf8zgqiUKo9/FJN26y7Fpvy1IODiBInDrKZ" + "RvNfqemCf7o3+Cp00OmF5ey"; /** * Ensures that the Directory Server is running before executing the * testcases. * * @throws Exception If an unexpected problem occurs. */ @BeforeClass public void startServer() throws Exception { TestCaseUtils.startServer(); TestCaseUtils.initializeTestBackend(true); } /** * Test to verify an ADD of the binary attributes using a V3 * protocol. * @throws Exception If an unexpected problem occurs. */ @Test public void binaryAttributeAddV3() throws Exception { //Add a binary attribute both with or without the binary option. String filePath = TestCaseUtils.createTempFile( "dn: uid=user.1,o=test", "objectClass: inetOrgPerson", "uid: user.1", "sn: 1", "cn: user 1", "userCertificate:: "+CERT ); String[] args = new String [] { "-h", "127.0.0.1", "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), "-D","cn=directory manager", "-w","password", "-a", "-f", filePath }; int err = LDAPModify.mainModify(args, false, null,null); assertEquals(err,0); //ADD with ;binary option. filePath = TestCaseUtils.createTempFile( "dn: uid=user.2,o=test", "objectClass: inetOrgPerson", "uid: user.2", "sn: 2", "cn: user 2", "userCertificate;binary:: "+CERT ); args = new String [] { "-h", "127.0.0.1", "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), "-D","cn=directory manager", "-w","password", "-a", "-f", filePath }; err = LDAPModify.mainModify(args, false, null,null); assertEquals(err,0); } /** * Test to verify an ADD of a non-binary attribute with the ;binary * transfer option using a V3 protocol. * @throws Exception If an unexpected problem occurs. */ @Test public void nonBinaryAttributeAddV3() throws Exception { String filePath = TestCaseUtils.createTempFile( "dn: uid=user.3,o=test", "objectClass: inetOrgPerson", "uid: user.3", "sn: 3", "cn: user 3", "cn;binary: common name" ); String[] args = new String [] { "-h", "127.0.0.1", "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), "-D","cn=directory manager", "-w","password", "-a", "-f", filePath, }; int err = LDAPModify.mainModify(args, false, null,null); assertFalse(err==0); } /** * Test to verify a SEARCH using the ;binary transfer option using a V3 * protocol. * @throws Exception If an unexpected problem occurs. */ @Test(dependsOnMethods = {"org.opends.server.protocols.ldap."+ "LDAPBinaryOptionTestCase.binaryAttributeAddV3"}) public void binaryAttributeSearchV3() throws Exception { SearchRequest request = newSearchRequest("o=test", SearchScope.WHOLE_SUBTREE, "(uid=user.1)"); InternalSearchOperation searchOperation = getRootConnection().processSearch(request); assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS); List<SearchResultEntry> entries = searchOperation.getSearchEntries(); SearchResultEntry e = entries.get(0); assertNotNull(e); List<Attribute> attrs = e.getAttribute("usercertificate"); Attribute a = attrs.get(0); assertNotNull(a); assertTrue(a.getOptions().contains("binary")); } /** * Test to verify a SEARCH using the ;binary transfer option using a V3 * protocol for a non-binary attribute. * @throws Exception If an unexpected problem occurs. */ @Test(dependsOnMethods = {"org.opends.server.protocols.ldap."+ "LDAPBinaryOptionTestCase.binaryAttributeAddV3"}) public void invalidBinaryAttributeSearchV3() throws Exception { SearchRequest request = newSearchRequest("o=test", SearchScope.WHOLE_SUBTREE, "(uid=user.1)") .addAttribute("cn;binary"); InternalSearchOperation searchOperation = getRootConnection().processSearch(request); assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS); List<SearchResultEntry> entries = searchOperation.getSearchEntries(); SearchResultEntry e = entries.get(0); assertNotNull(e); List<Attribute> list = e.getAttributes(); assertEquals(list.size(), 0); } /** * Test to verify an ADD and SEARCH using the ;binary transfer option using a * V2 protocol. * @throws Exception If an unexpected problem occurs. */ @Test public void binaryOptionUsingV2() throws Exception { //Construct a V2 connection. Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s); org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s); try { BindRequestProtocolOp bindRequest = new BindRequestProtocolOp( ByteString.valueOfUtf8("cn=Directory Manager"), 2, ByteString.valueOfUtf8("password")); LDAPMessage message = new LDAPMessage(1, bindRequest); w.writeMessage(message); message = r.readMessage(); BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp(); assertEquals(bindResponse.getResultCode(), 0); ArrayList<RawAttribute> addAttrs = new ArrayList<>(); addAttrs.add(RawAttribute.create("objectClass", "inetOrgPerson")); addAttrs.add(RawAttribute.create("uid", "user.7")); addAttrs.add(RawAttribute.create("cn", "user 7")); addAttrs.add(RawAttribute.create("sn", "sn#1")); addAttrs.add(RawAttribute.create("sn;x-foo", "sn#2")); addAttrs.add(RawAttribute.create("sn;lang-fr", "sn#3")); addAttrs.add(RawAttribute.create("userCertificate;binary", ByteString.wrap(Base64.decode(CERT)))); AddRequestProtocolOp addRequest = new AddRequestProtocolOp(ByteString.valueOfUtf8("uid=user.7,o=test"), addAttrs); message = new LDAPMessage(2, addRequest); w.writeMessage(message); message = r.readMessage(); AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp(); assertEquals(addResponse.getResultCode(),0); //Create a SEARCH request to search for this added entry. LinkedHashSet<String> attrs = new LinkedHashSet<>(); //Request only the interesting attributes. attrs.add("sn"); attrs.add("userCertificate;binary"); SearchRequestProtocolOp searchRequest = new SearchRequestProtocolOp(ByteString.valueOfUtf8("o=test"), SearchScope.WHOLE_SUBTREE, DereferenceAliasesPolicy.NEVER, 0, 0, false, LDAPFilter.decode("(uid=user.7)"), attrs); message = new LDAPMessage(2, searchRequest); w.writeMessage(message); SearchResultEntryProtocolOp searchResultEntry = null; SearchResultDoneProtocolOp searchResultDone = null; while (searchResultDone == null) { message = r.readMessage(); switch (message.getProtocolOpType()) { case LDAPConstants.OP_TYPE_SEARCH_RESULT_ENTRY: searchResultEntry = message.getSearchResultEntryProtocolOp(); break; case LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE: searchResultDone = message.getSearchResultDoneProtocolOp(); assertEquals(searchResultDone.getResultCode(), LDAPResultCode.SUCCESS); break; } } assertNotNull(searchResultEntry); boolean certWithNoOption = false; boolean snWithMultiVal = false; for(LDAPAttribute a:searchResultEntry.getAttributes()) { //Shouldn't be userCertificate;binary. if ("userCertificate".equalsIgnoreCase(a.getAttributeType())) { certWithNoOption=true; } else if ("sn".equalsIgnoreCase(a.getAttributeType())) { for (ByteString v : a.getValues()) { String val = v.toString(); snWithMultiVal = val.equals("sn#1") || val.equals("sn#2") || val.equals("sn#3"); } } } assertTrue(snWithMultiVal && certWithNoOption); } finally { StaticUtils.close(r, w); StaticUtils.close(s); } } /** * Test to verify that the DB stores the binary option by * exporting the LDIF and searching for the binary keyword. * @throws Exception If an unexpected problem occurs. */ @Test(dependsOnMethods = {"org.opends.server.protocols.ldap."+ "LDAPBinaryOptionTestCase.binaryAttributeAddV3"}) public void exportAndValidateBinaryAttribute() throws Exception { //Ensure that the entry exists. String args[] = new String [] { "--noPropertiesFile", "-h", "127.0.0.1", "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), "-b", "o=test", "(uid=user.1)" }; assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0); exportBackend(); assertTrue(ldif.exists()); assertTrue(containsBinary()); } /** * Test to verify that the server adds the binary option by * importing an LDIF both with or without the binary option. * @throws Exception If an unexpected problem occurs. */ @Test(dependsOnMethods = {"org.opends.server.protocols.ldap."+ "LDAPBinaryOptionTestCase.exportAndValidateBinaryAttribute"}) public void ImportAndValidateBinaryAttribute() throws Exception { //This testcase uses the exported ldif in exportAndValidBinaryAttribute //testcase. It imports the ldif after cleaning up the database and verifies //that the binary option is present in the binary attributes. After that, it //modifies the binary option from the ldif and re-imports it.A re-export of //the last import should have the binary option even though it wasn't //there in the imported ldif. assertTrue(ldif.exists()); importLDIF(); assertTrue(containsBinary()); //Remove the binary option and re-import it. FileReader reader = new FileReader(ldif); BufferedReader buf = new BufferedReader(reader); StringBuilder builder = new StringBuilder(); String userCert = "userCertificate;binary"; String line = null; while((line=buf.readLine())!=null) { if(line.startsWith(userCert)) { builder.append("userCertificate:"); builder.append(line, userCert.length()+1, line.length()); } else { builder.append(line); } builder.append("\n"); } buf.close(); ldif.delete(); ldif = new File(TestCaseUtils.createTempFile(builder.toString())); importLDIF(); //Re-export it. exportBackend(); assertTrue(containsBinary()); ldif.delete(); } /** * Test to verify a MODIFY using the ;binary transfer option using V3 * protocol. * @throws Exception If an unexpected problem occurs. */ @Test public void binaryModifyV3() throws Exception { String filePath = TestCaseUtils.createTempFile( "dn: uid=user.4,o=test", "objectClass: inetOrgPerson", "uid: user.4", "sn: 4", "cn: user 4" ); String[] args = new String [] { "-h", "127.0.0.1", "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), "-D","cn=directory manager", "-w","password", "-a", "-f", filePath, }; int err = LDAPModify.mainModify(args, false, null,null); assertEquals(err,0); filePath = TestCaseUtils.createTempFile( "dn: uid=user.4,o=test", "changetype: modify", "add: usercertificate;binary", "userCertificate;binary:: " + CERT); args = new String[] { "-h", "127.0.0.1", "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), "-D","cn=directory manager", "-w","password", "-f", filePath, }; err = LDAPModify.mainModify(args, false, null,null); assertEquals(err,0); } /** * Utility method to verify if the LDIF file contains binary option. * @return {@code true} if binary option is found in the LDIF * , or {@code false} if not. * @throws Exception If an unexpected problem occurs. */ private boolean containsBinary() throws Exception { FileReader reader = new FileReader(ldif); BufferedReader buf = new BufferedReader(reader); String line = null; boolean found=false; while((line=buf.readLine())!=null) { if(line.startsWith("userCertificate;binary")) { found = true; } } buf.close(); return found; } /** * Utility method to export the database into an LDIF file. * @throws Exception If an unexpected problem occurs. */ private void exportBackend() throws Exception { //Initialize necessary instance variables. if(ldif==null) { ldif = File.createTempFile("LDAPBinaryOptionTestCase", ".ldif"); } exportConfig = new LDIFExportConfig(ldif.getAbsolutePath(), ExistingFileBehavior.OVERWRITE); backend = DirectoryServer.getBackend("test"); backend.exportLDIF(exportConfig); } /** * Utility method to import the LDIF into the database. * @throws Exception If an unexpected problem occurs. */ private void importLDIF() throws Exception { importConfig = new LDIFImportConfig(ldif.getAbsolutePath()); TestCaseUtils.initializeTestBackend(false); backend = DirectoryServer.getBackend("test"); backend.importLDIF(importConfig, DirectoryServer.getInstance().getServerContext()); } }