blob: da6299340bc4f2508bfbcaea2d84187640ffa48e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.server.operations.search;
import static org.apache.directory.server.integ.ServerIntegrationUtils.getClientApiConnection;
import static org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContext;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.naming.InvalidNameException;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapContext;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
import org.apache.directory.server.annotations.CreateLdapServer;
import org.apache.directory.server.annotations.CreateTransport;
import org.apache.directory.server.core.annotations.ApplyLdifs;
import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
import org.apache.directory.server.core.integ.FrameworkRunner;
import org.apache.directory.server.ldap.LdapServer;
import org.apache.directory.shared.ldap.model.message.controls.SubentriesImpl;
import org.apache.directory.shared.ldap.model.message.controls.Subentries;
import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
import org.apache.directory.shared.ldap.model.cursor.Cursor;
import org.apache.directory.shared.ldap.model.entry.DefaultEntry;
import org.apache.directory.shared.ldap.model.entry.Entry;
import org.apache.directory.shared.ldap.model.exception.LdapException;
import org.apache.directory.shared.ldap.model.filter.SearchScope;
import org.apache.directory.shared.ldap.model.message.Control;
import org.apache.directory.shared.ldap.model.message.Response;
import org.apache.directory.shared.ldap.model.message.SearchRequest;
import org.apache.directory.shared.ldap.model.message.SearchRequestImpl;
import org.apache.directory.shared.ldap.model.name.Dn;
import org.apache.directory.shared.ldap.util.JndiUtils;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Testcase with different modify operations on a person entry. Each includes a
* single add op only. Created to demonstrate DIREVE-241 ("Adding an already
* existing attribute value with a modify operation does not cause an error.").
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
@RunWith(FrameworkRunner.class)
@CreateLdapServer(transports =
{ @CreateTransport(protocol = "LDAP") })
@ApplyLdifs(
{
// Entry # 0
"dn: cn=Kate Bush,ou=system",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"objectClass: strongAuthenticationUser",
"objectClass: top",
"userCertificate:: NFZOXw==",
"cn: Kate Bush",
"description: this is a person",
"sn: Bush",
"jpegPhoto:: /9j/4AAQSkZJRgABAQEASABIAAD/4QAWRXhpZgAATU0AKgAAAAgAAAAAAAD//gAX",
" Q3JlYXRlZCB3aXRoIFRoZSBHSU1Q/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgxIyUdKDozPTw",
" 5Mzg3QEhcTkBEV0U3OFBtUVdfYmdoZz5NcXlwZHhcZWdj/9sAQwEREhIYFRgvGhovY0I4QmNjY2",
" NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2Nj/8AAEQgAAQABA",
" wEiAAIRAQMRAf/EABUAAQEAAAAAAAAAAAAAAAAAAAAF/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/E",
" ABUBAQEAAAAAAAAAAAAAAAAAAAUG/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8",
" AigC14//Z",
// Entry # 2
"dn: cn=Tori Amos,ou=system",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"objectClass: strongAuthenticationUser",
"objectClass: top",
"userCertificate:: NFZOXw==",
"cn: Tori Amos",
"description: an American singer-songwriter",
"sn: Amos",
"jpegPhoto:: /9j/4AAQSkZJRgABAQEASABIAAD/4QAWRXhpZgAATU0AKgAAAAgAAAAAAAD//gAX",
" Q3JlYXRlZCB3aXRoIFRoZSBHSU1Q/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgxIyUdKDozPTw",
" 5Mzg3QEhcTkBEV0U3OFBtUVdfYmdoZz5NcXlwZHhcZWdj/9sAQwEREhIYFRgvGhovY0I4QmNjY2",
" NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2Nj/8AAEQgAAQABA",
" wEiAAIRAQMRAf/EABUAAQEAAAAAAAAAAAAAAAAAAAAF/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/E",
" ABUBAQEAAAAAAAAAAAAAAAAAAAUG/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8",
" AigC14//Z",
// Entry # 3
"dn: cn=Rolling-Stones,ou=system",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"objectClass: strongAuthenticationUser",
"objectClass: top",
"userCertificate:: NFZOXw==",
"cn: Rolling-Stones",
"description: an English singer-songwriter",
"sn: Jagger",
"jpegPhoto:: /9j/4AAQSkZJRgABAQEASABIAAD/4QAWRXhpZgAATU0AKgAAAAgAAAAAAAD//gAX",
" Q3JlYXRlZCB3aXRoIFRoZSBHSU1Q/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgxIyUdKDozPTw",
" 5Mzg3QEhcTkBEV0U3OFBtUVdfYmdoZz5NcXlwZHhcZWdj/9sAQwEREhIYFRgvGhovY0I4QmNjY2",
" NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2Nj/8AAEQgAAQABA",
" wEiAAIRAQMRAf/EABUAAQEAAAAAAAAAAAAAAAAAAAAF/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/E",
" ABUBAQEAAAAAAAAAAAAAAAAAAAUG/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8",
" AigC14//Z",
// Entry # 4
"dn: cn=Heather Nova,ou=system",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"objectClass: strongAuthenticationUser",
"objectClass: top",
"userCertificate:: NFZOXw==",
"cn: Heather Nova",
"sn: Nova",
"jpegPhoto:: /9j/4AAQSkZJRgABAQEASABIAAD/4QAWRXhpZgAATU0AKgAAAAgAAAAAAAD//gAX",
" Q3JlYXRlZCB3aXRoIFRoZSBHSU1Q/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgxIyUdKDozPTw",
" 5Mzg3QEhcTkBEV0U3OFBtUVdfYmdoZz5NcXlwZHhcZWdj/9sAQwEREhIYFRgvGhovY0I4QmNjY2",
" NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2Nj/8AAEQgAAQABA",
" wEiAAIRAQMRAf/EABUAAQEAAAAAAAAAAAAAAAAAAAAF/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/E",
" ABUBAQEAAAAAAAAAAAAAAAAAAAUG/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8",
" AigC14//Z",
// Entry #5
"dn: cn=Janis Joplin,ou=system",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"objectClass: top",
"objectClass: strongAuthenticationUser",
"cn: Janis Joplin",
"sn: Joplin",
"userCertificate:: ",
// Entry #6
"dn: cn=Kim Wilde,ou=system",
"objectClass: person",
"objectClass: top",
"cn: Kim Wilde",
"sn: Wilde",
"description: an American singer-songwriter+sexy blond"
})
public class SearchIT extends AbstractLdapTestUnit
{
private static final String BASE = "ou=system";
public static LdapServer ldapServer;
private static final String RDN = "cn=Tori Amos";
private static final String RDN2 = "cn=Rolling-Stones";
private static final String HEATHER_RDN = "cn=Heather Nova";
private static final String FILTER = "(objectclass=*)";
private static final byte[] JPEG = new byte[]
{ ( byte ) 0xff, ( byte ) 0xd8, ( byte ) 0xff, ( byte ) 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, ( byte ) 0xff, ( byte ) 0xe1, 0x00, 0x16, 0x45, 0x78, 0x69,
0x66, 0x00, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
( byte ) 0xff, ( byte ) 0xfe, 0x00, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74,
0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4d, 0x50, ( byte ) 0xff, ( byte ) 0xdb, 0x00, 0x43, 0x00,
0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18,
0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48,
0x5c, 0x4e, 0x40, 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e,
0x4d, 0x71, 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, ( byte ) 0xff, ( byte ) 0xdb, 0x00, 0x43, 0x01,
0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, ( byte ) 0xff, ( byte ) 0xc0, 0x00, 0x11, 0x08,
0x00, 0x01, 0x00, 0x01, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, ( byte ) 0xff,
( byte ) 0xc4, 0x00, 0x15, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ( byte ) 0xff, ( byte ) 0xc4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ( byte ) 0xff, ( byte ) 0xc4,
0x00, 0x15, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x05, 0x06, ( byte ) 0xff, ( byte ) 0xc4, 0x00, 0x14, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ( byte ) 0xff, ( byte ) 0xda, 0x00, 0x0c, 0x03,
0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, ( byte ) 0x8a, 0x00, ( byte ) 0xb5, ( byte ) 0xe3,
( byte ) 0xff, ( byte ) 0xd9, };
/**
* Creation of required attributes of a person entry.
*/
private Attributes getPersonAttributes( String sn, String cn )
{
Attributes attributes = new BasicAttributes( true );
Attribute attribute = new BasicAttribute( "objectClass" );
attribute.add( "top" );
attribute.add( "person" );
attribute.add( "organizationalPerson" );
attribute.add( "inetOrgPerson" );
attributes.put( attribute );
attributes.put( "cn", cn );
attributes.put( "sn", sn );
attributes.put( "jpegPhoto", JPEG );
return attributes;
}
private void checkForAttributes( Attributes attrs, String[] attrNames )
{
for ( String attrName : attrNames )
{
assertNotNull( "Check if attr " + attrName + " is present", attrs.get( attrName ) );
}
}
/**
* For DIRSERVER-715 and part of DIRSERVER-169. May include other tests
* for binary attribute based searching.
*/
@Test
public void testSearchByBinaryAttribute() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( ldapServer ).lookup( BASE );
byte[] certData = new byte[]
{ 0x34, 0x56, 0x4e, 0x5f };
// Search for kate by cn first
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
NamingEnumeration<SearchResult> enm = ctx.search( "", "(cn=Kate Bush)", controls );
assertTrue( enm.hasMore() );
SearchResult sr = enm.next();
assertNotNull( sr );
assertFalse( enm.hasMore() );
assertEquals( "cn=Kate Bush", sr.getName() );
enm = ctx.search( "", "(&(cn=Kate Bush)(userCertificate={0}))", new Object[]
{ certData }, controls );
assertTrue( enm.hasMore() );
sr = ( SearchResult ) enm.next();
assertNotNull( sr );
assertFalse( enm.hasMore() );
assertEquals( "cn=Kate Bush", sr.getName() );
enm = ctx.search( "", "(userCertificate=\\34\\56\\4E\\5F)", controls );
assertTrue( enm.hasMore() );
int count = 0;
Set<String> expected = new HashSet<String>();
expected.add( "cn=Kate Bush" );
expected.add( "cn=Tori Amos" );
expected.add( "cn=Rolling-Stones" );
expected.add( "cn=Heather Nova" );
while ( enm.hasMore() )
{
count++;
sr = ( SearchResult ) enm.next();
assertNotNull( sr );
assertTrue( expected.contains( sr.getName() ) );
expected.remove( sr.getName() );
}
assertEquals( 4, count );
assertFalse( enm.hasMore() );
assertEquals( 0, expected.size() );
}
@Test
public void testSearch() throws Exception
{
LdapContext ctx = getWiredContext( ldapServer );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.OBJECT_SCOPE );
controls.setTimeLimit( 10 );
try
{
ctx.search( "myBadDN", "(objectClass=*)", controls );
fail(); // We should get an exception here
}
catch ( InvalidNameException ine )
{
// Expected.
}
catch ( NamingException ne )
{
fail();
}
catch ( Exception e )
{
fail();
}
try
{
controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setTimeLimit( 10 );
NamingEnumeration<SearchResult> result = ctx.search( "ou=system", "(objectClass=*)", controls );
assertTrue( result.hasMore() );
}
catch ( InvalidNameException ine )
{
fail();
// Expected.
}
catch ( NamingException ne )
{
fail();
}
}
/**
* Performs a single level search from ou=system base and
* returns the set of DNs found.
*/
private Set<String> search( String filter ) throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
NamingEnumeration<SearchResult> ii = ctx.search( "", filter, controls );
// collect all results
HashSet<String> results = new HashSet<String>();
while ( ii.hasMore() )
{
SearchResult result = ii.next();
results.add( result.getName() );
}
return results;
}
@Test
public void testDirserver635() throws Exception
{
// -------------------------------------------------------------------
Set<String> results = search( "(|(cn=Kate*)(cn=Tori*))" );
assertEquals( "returned size of results", 2, results.size() );
assertTrue( "contains cn=Tori Amos", results.contains( "cn=Tori Amos" ) );
assertTrue( "contains cn=Kate Bush", results.contains( "cn=Kate Bush" ) );
// -------------------------------------------------------------------
results = search( "(|(cn=*Amos)(cn=Kate*))" );
assertEquals( "returned size of results", 2, results.size() );
assertTrue( "contains cn=Tori Amos", results.contains( "cn=Tori Amos" ) );
assertTrue( "contains cn=Kate Bush", results.contains( "cn=Kate Bush" ) );
// -------------------------------------------------------------------
results = search( "(|(cn=Kate Bush)(cn=Tori*))" );
assertEquals( "returned size of results", 2, results.size() );
assertTrue( "contains cn=Tori Amos", results.contains( "cn=Tori Amos" ) );
assertTrue( "contains cn=Kate Bush", results.contains( "cn=Kate Bush" ) );
// -------------------------------------------------------------------
results = search( "(|(cn=*Amos))" );
assertEquals( "returned size of results", 1, results.size() );
assertTrue( "contains cn=Tori Amos", results.contains( "cn=Tori Amos" ) );
}
/**
* Search operation with a base Dn which contains a BER encoded value.
*/
@Test
public void testSearchWithBackslashEscapedBase() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
// create additional entry
Attributes attributes = this.getPersonAttributes( "Ferry", "Bryan Ferry" );
ctx.createSubcontext( "sn=Ferry", attributes );
SearchControls sctls = new SearchControls();
sctls.setSearchScope( SearchControls.OBJECT_SCOPE );
String filter = "(cn=Bryan Ferry)";
// sn=Ferry with BEROctetString values
String base = "sn=\\46\\65\\72\\72\\79";
try
{
// Check entry
NamingEnumeration<SearchResult> enm = ctx.search( base, filter, sctls );
assertTrue( enm.hasMore() );
while ( enm.hasMore() )
{
SearchResult sr = enm.next();
Attributes attrs = sr.getAttributes();
Attribute sn = attrs.get( "sn" );
assertNotNull( sn );
assertTrue( sn.contains( "Ferry" ) );
}
}
catch ( Exception e )
{
fail( e.getMessage() );
}
}
/**
* Add a new attribute to a person entry.
*
* @throws LdapException
*/
@Test
public void testSearchValue() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
// Setting up search controls for compare op
SearchControls ctls = new SearchControls();
ctls.setReturningAttributes( new String[]
{ "*" } ); // no attributes
ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
// Search for all entries
NamingEnumeration<SearchResult> results = ctx.search( RDN, "(cn=*)", ctls );
assertTrue( results.hasMore() );
results = ctx.search( RDN2, "(cn=*)", ctls );
assertTrue( results.hasMore() );
// Search for all entries ending by Amos
results = ctx.search( RDN, "(cn=*Amos)", ctls );
assertTrue( results.hasMore() );
results = ctx.search( RDN2, "(cn=*Amos)", ctls );
assertFalse( results.hasMore() );
// Search for all entries ending by amos
results = ctx.search( RDN, "(cn=*amos)", ctls );
assertTrue( results.hasMore() );
results = ctx.search( RDN2, "(cn=*amos)", ctls );
assertFalse( results.hasMore() );
// Search for all entries starting by Tori
results = ctx.search( RDN, "(cn=Tori*)", ctls );
assertTrue( results.hasMore() );
results = ctx.search( RDN2, "(cn=Tori*)", ctls );
assertFalse( results.hasMore() );
// Search for all entries starting by tori
results = ctx.search( RDN, "(cn=tori*)", ctls );
assertTrue( results.hasMore() );
results = ctx.search( RDN2, "(cn=tori*)", ctls );
assertFalse( results.hasMore() );
// Search for all entries containing ori
results = ctx.search( RDN, "(cn=*ori*)", ctls );
assertTrue( results.hasMore() );
results = ctx.search( RDN2, "(cn=*ori*)", ctls );
assertFalse( results.hasMore() );
// Search for all entries containing o and i
results = ctx.search( RDN, "(cn=*o*i*)", ctls );
assertTrue( results.hasMore() );
results = ctx.search( RDN2, "(cn=*o*i*)", ctls );
assertTrue( results.hasMore() );
// Search for all entries containing o, space and o
results = ctx.search( RDN, "(cn=*o* *o*)", ctls );
assertTrue( results.hasMore() );
results = ctx.search( RDN2, "(cn=*o* *o*)", ctls );
assertFalse( results.hasMore() );
results = ctx.search( RDN2, "(cn=*o*-*o*)", ctls );
assertTrue( results.hasMore() );
// Search for all entries starting by To and containing A
results = ctx.search( RDN, "(cn=To*A*)", ctls );
assertTrue( results.hasMore() );
results = ctx.search( RDN2, "(cn=To*A*)", ctls );
assertFalse( results.hasMore() );
// Search for all entries ending by os and containing ri
results = ctx.search( RDN, "(cn=*ri*os)", ctls );
assertTrue( results.hasMore() );
results = ctx.search( RDN2, "(cn=*ri*os)", ctls );
assertFalse( results.hasMore() );
}
/**
* Search operation with a base Dn with quotes
*
@Test
public void testSearchWithQuotesInBase() throws NamingException {
SearchControls sctls = new SearchControls();
sctls.setSearchScope(SearchControls.OBJECT_SCOPE);
String filter = "(cn=Tori Amos)";
// cn="Tori Amos" (with quotes)
String base = "cn=\"Tori Amos\"";
try {
// Check entry
NamingEnumeration<SearchResult> enm = ctx.search( base, filter, sctls );
assertTrue( enm.hasMore() );
while ( enm.hasMore() ) {
SearchResult sr = enm.next();
Attributes attrs = sr.getAttributes();
Attribute sn = attrs.get("sn");
assertNotNull(sn);
assertTrue( sn.contains( "Amos" ) );
}
} catch (Exception e) {
fail( e.getMessage() );
}
}
/**
* Tests for <a href="http://issues.apache.org/jira/browse/DIRSERVER-645">
* DIRSERVER-645<\a>: Wrong search FILTER evaluation with AND
* operator and undefined operands.
*/
@Test
public void testUndefinedAvaInBranchFilters() throws Exception
{
// -------------------------------------------------------------------
Set<String> results = search( "(|(sn=Bush)(numberOfOctaves=4))" );
assertEquals( "returned size of results", 1, results.size() );
assertTrue( "contains cn=Kate Bush", results.contains( "cn=Kate Bush" ) );
// if numberOfOctaves is undefined then this whole FILTER is undefined
results = search( "(&(sn=Bush)(numberOfOctaves=4))" );
assertEquals( "returned size of results", 0, results.size() );
}
@Test
public void testSearchSchema() throws Exception
{
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.OBJECT_SCOPE );
controls.setReturningAttributes( new String[]
{ "objectClasses" } );
LdapContext ctx = getWiredContext( ldapServer );
NamingEnumeration<SearchResult> results = ctx.search( "cn=schema", "objectClass=subschema", controls );
assertTrue( results.hasMore() );
SearchResult result = results.next();
assertNotNull( result );
assertFalse( results.hasMore() );
NamingEnumeration<? extends Attribute> attrs = result.getAttributes().getAll();
while ( attrs.hasMoreElements() )
{
Attribute attr = ( Attribute ) attrs.next();
String ID = attr.getID();
assertEquals( "objectClasses", ID );
}
assertNotNull( result.getAttributes().get( "objectClasses" ) );
assertEquals( 1, result.getAttributes().size() );
}
/**
* Creates an access decorator subentry under ou=system whose subtree covers
* the entire naming context.
*
* @param cn the common name and rdn for the subentry
* @param subtree the subtreeSpecification for the subentry
* @param aciItem the prescriptive ACI attribute value
* @throws NamingException if there is a problem creating the subentry
*/
private void createAccessControlSubentry( String cn, String subtree, String aciItem ) throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
DirContext adminCtx = ctx;
// modify ou=system to be an AP for an A/C AA if it is not already
Attributes ap = adminCtx.getAttributes( "", new String[]
{ "administrativeRole" } );
Attribute administrativeRole = ap.get( "administrativeRole" );
if ( administrativeRole == null || !administrativeRole.contains( "accessControlSpecificArea" ) )
{
Attributes changes = new BasicAttributes( "administrativeRole", "accessControlSpecificArea", true );
adminCtx.modifyAttributes( "", DirContext.ADD_ATTRIBUTE, changes );
}
// now add the A/C subentry below ou=system
Attributes subentry = new BasicAttributes( "cn", cn, true );
Attribute objectClass = new BasicAttribute( "objectClass" );
subentry.put( objectClass );
objectClass.add( "top" );
objectClass.add( SchemaConstants.SUBENTRY_OC );
objectClass.add( "accessControlSubentry" );
subentry.put( "subtreeSpecification", subtree );
subentry.put( "prescriptiveACI", aciItem );
adminCtx.createSubcontext( "cn=" + cn, subentry );
}
/**
* Test case to demonstrate DIRSERVER-705 ("object class top missing in search
* result, if scope is base and attribute objectClass is requested explicitly").
*/
@Test
public void testAddWithObjectclasses() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls ctls = new SearchControls();
ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
ctls.setReturningAttributes( new String[]
{ "objectclass" } );
String filter = "(objectclass=*)";
String rdn = "cn=Kim Wilde";
NamingEnumeration<SearchResult> result = ctx.search( rdn, filter, ctls );
if ( result.hasMore() )
{
SearchResult entry = result.next();
Attributes heatherReloaded = entry.getAttributes();
Attribute loadedOcls = heatherReloaded.get( "objectClass" );
assertNotNull( loadedOcls );
assertTrue( loadedOcls.contains( "person" ) );
assertTrue( loadedOcls.contains( "top" ) );
}
else
{
fail( "entry " + rdn + " not found" );
}
ctx.destroySubcontext( rdn );
}
/**
* Test case to demonstrate DIRSERVER-705 ("object class top missing in search
* result, if scope is base and attribute objectClass is requested explicitly").
*/
@Test
public void testAddWithMissingObjectclasses() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
String rdn = "cn=Kate Bush";
SearchControls ctls = new SearchControls();
ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
ctls.setReturningAttributes( new String[]
{ "objectclass" } );
String filter = "(objectclass=*)";
NamingEnumeration<SearchResult> result = ctx.search( rdn, filter, ctls );
if ( result.hasMore() )
{
SearchResult entry = result.next();
Attributes kateReloaded = entry.getAttributes();
Attribute loadedOcls = kateReloaded.get( "objectClass" );
assertNotNull( loadedOcls );
assertTrue( loadedOcls.contains( "top" ) );
assertTrue( loadedOcls.contains( "person" ) );
assertTrue( loadedOcls.contains( "organizationalPerson" ) );
}
else
{
fail( "entry " + rdn + " not found" );
}
ctx.destroySubcontext( rdn );
}
@Test
public void testSubentryControl() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
// create a real access decorator subentry
createAccessControlSubentry( "anyBodyAdd", "{}", "{ " + " identificationTag \"addAci\", "
+ " precedence 14, " + " authenticationLevel none, " + " itemOrUserFirst userFirst: " + " { "
+ " userClasses " + " { " + " allUsers " + " }, " + " userPermissions " + " { "
+ " { " + " protectedItems " + " { " + " entry, allUserAttributeTypesAndValues"
+ " }, " + " grantsAndDenials " + " { " + " grantAdd, grantBrowse "
+ " } " + " } " + " } " + " } " + "}" );
// prepare the subentry decorator to make the subentry visible
Subentries ctl = new SubentriesImpl();
ctl.setVisibility( true );
Control[] reqControls = new Control[]
{ ctl };
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
ctx.setRequestControls( JndiUtils.toJndiControls( ldapServer.getDirectoryService().getLdapCodecService(),
reqControls ) );
NamingEnumeration<SearchResult> enm = ctx.search( "", "(objectClass=*)", searchControls );
Set<String> results = new HashSet<String>();
while ( enm.hasMore() )
{
SearchResult result = enm.next();
results.add( result.getName() );
}
assertEquals( "expected results size of", 1, results.size() );
assertTrue( results.contains( "cn=anyBodyAdd" ) );
}
/**
* Create a person entry with multivalued Rdn and check its content. This
* testcase was created to demonstrate DIRSERVER-628.
*/
@Test
public void testMultiValuedRdnContent() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
Attributes attrs = getPersonAttributes( "Bush", "Kate Bush" );
String rdn = "cn=Kate Bush+sn=Bush";
ctx.createSubcontext( rdn, attrs );
SearchControls sctls = new SearchControls();
sctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
String filter = "(sn=Bush)";
String base = "";
NamingEnumeration<SearchResult> enm = ctx.search( base, filter, sctls );
while ( enm.hasMore() )
{
SearchResult sr = enm.next();
attrs = sr.getAttributes();
Attribute cn = sr.getAttributes().get( "cn" );
assertNotNull( cn );
assertTrue( cn.contains( "Kate Bush" ) );
Attribute sn = sr.getAttributes().get( "sn" );
assertNotNull( sn );
assertTrue( sn.contains( "Bush" ) );
}
ctx.destroySubcontext( rdn );
}
/**
* Create a person entry with multivalued Rdn and check its name.
*/
@Test
public void testMultiValuedRdnName() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
Attributes attrs = getPersonAttributes( "Bush", "Kate Bush" );
String rdn = "cn=Kate Bush+sn=Bush";
DirContext entry = ctx.createSubcontext( rdn, attrs );
String nameInNamespace = entry.getNameInNamespace();
SearchControls sctls = new SearchControls();
sctls.setSearchScope( SearchControls.OBJECT_SCOPE );
String filter = "(sn=Bush)";
String base = rdn;
NamingEnumeration<SearchResult> enm = ctx.search( base, filter, sctls );
if ( enm.hasMore() )
{
SearchResult sr = enm.next();
assertNotNull( sr );
assertEquals( "Name in namespace", nameInNamespace, sr.getNameInNamespace() );
}
else
{
fail( "Entry not found:" + nameInNamespace );
}
ctx.destroySubcontext( rdn );
}
@Test
public void testSearchJpeg() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
NamingEnumeration<SearchResult> res = ctx.search( "", "(cn=Tori*)", controls );
// collect all results
while ( res.hasMore() )
{
SearchResult result = res.next();
Attributes attrs = result.getAttributes();
NamingEnumeration<? extends Attribute> all = attrs.getAll();
while ( all.hasMoreElements() )
{
Attribute attr = all.next();
if ( "jpegPhoto".equalsIgnoreCase( attr.getID() ) )
{
byte[] jpegVal = ( byte[] ) attr.get();
assertTrue( Arrays.equals( jpegVal, JPEG ) );
}
}
}
}
@Test
public void testSearchOID() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
NamingEnumeration<SearchResult> res = ctx.search( "", "(2.5.4.3=Tori*)", controls );
// ensure that the entry "cn=Tori Amos" was found
assertTrue( res.hasMore() );
SearchResult result = ( SearchResult ) res.next();
// ensure that result is not null
assertNotNull( result );
String rdn = result.getName();
// ensure that the entry "cn=Tori Amos" was found
assertEquals( "cn=Tori Amos", rdn );
// ensure that no other value was found
assertFalse( res.hasMore() );
}
@Test
public void testSearchAttrCN() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setReturningAttributes( new String[]
{ "cn" } );
NamingEnumeration<SearchResult> res = ctx.search( "", "(commonName=Tori*)", controls );
assertTrue( res.hasMore() );
SearchResult result = res.next();
// ensure that result is not null
assertNotNull( result );
Attributes attrs = result.getAttributes();
// ensure the one and only attribute is "cn"
assertEquals( 1, attrs.size() );
assertNotNull( attrs.get( "cn" ) );
assertEquals( 1, attrs.get( "cn" ).size() );
assertEquals( "Tori Amos", ( String ) attrs.get( "cn" ).get() );
}
@Test
public void testSearchAttrName() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setReturningAttributes( new String[]
{ "name" } );
NamingEnumeration<SearchResult> res = ctx.search( "", "(commonName=Tori*)", controls );
assertTrue( res.hasMore() );
SearchResult result = res.next();
// ensure that result is not null
assertNotNull( result );
Attributes attrs = result.getAttributes();
// ensure that "cn" and "sn" are returned
assertEquals( 2, attrs.size() );
assertNotNull( attrs.get( "cn" ) );
assertEquals( 1, attrs.get( "cn" ).size() );
assertEquals( "Tori Amos", ( String ) attrs.get( "cn" ).get() );
assertNotNull( attrs.get( "sn" ) );
assertEquals( 1, attrs.get( "sn" ).size() );
assertEquals( "Amos", ( String ) attrs.get( "sn" ).get() );
}
@Test
public void testSearchAttrCommonName() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setReturningAttributes( new String[]
{ "commonName" } );
NamingEnumeration<SearchResult> res = ctx.search( "", "(commonName=Tori*)", controls );
assertTrue( res.hasMore() );
SearchResult result = res.next();
// ensure that result is not null
assertNotNull( result );
Attributes attrs = result.getAttributes();
// requested attribute was "commonName", but ADS returns "cn".
// Other servers do the following:
// - OpenLDAP: also return "cn"
// - Siemens DirX: return "commonName"
// - Sun Directory 5.2: return "commonName"
// ensure the one and only attribute is "cn"
assertEquals( 1, attrs.size() );
assertNotNull( attrs.get( "cn" ) );
assertEquals( 1, attrs.get( "cn" ).size() );
assertEquals( "Tori Amos", ( String ) attrs.get( "cn" ).get() );
}
@Test
public void testSearchAttrOID() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setReturningAttributes( new String[]
{ "2.5.4.3" } );
NamingEnumeration<SearchResult> res = ctx.search( "", "(commonName=Tori*)", controls );
assertTrue( res.hasMore() );
SearchResult result = res.next();
// ensure that result is not null
assertNotNull( result );
Attributes attrs = result.getAttributes();
// requested attribute was "2.5.4.3", but ADS returns "cn".
// Other servers do the following:
// - OpenLDAP: also return "cn"
// - Siemens DirX: also return "cn"
// - Sun Directory 5.2: return "2.5.4.3"
// ensure the one and only attribute is "cn"
assertEquals( 1, attrs.size() );
assertNotNull( attrs.get( "cn" ) );
assertEquals( 1, attrs.get( "cn" ).size() );
assertEquals( "Tori Amos", ( String ) attrs.get( "cn" ).get() );
}
@Test
public void testSearchAttrC_L() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
// create administrative area
Attributes aaAttrs = new BasicAttributes( true );
Attribute aaObjectClass = new BasicAttribute( "objectClass" );
aaObjectClass.add( "top" );
aaObjectClass.add( "organizationalUnit" );
aaObjectClass.add( "extensibleObject" );
aaAttrs.put( aaObjectClass );
aaAttrs.put( "ou", "Collective Area" );
aaAttrs.put( "administrativeRole", "collectiveAttributeSpecificArea" );
DirContext aaCtx = ctx.createSubcontext( "ou=Collective Area", aaAttrs );
// create subentry
Attributes subentry = new BasicAttributes( true );
Attribute objectClass = new BasicAttribute( "objectClass" );
objectClass.add( "top" );
objectClass.add( SchemaConstants.SUBENTRY_OC );
objectClass.add( "collectiveAttributeSubentry" );
subentry.put( objectClass );
subentry.put( "c-l", "Munich" );
subentry.put( "cn", "Collective Subentry" );
subentry.put( "subtreeSpecification", "{ }" );
aaCtx.createSubcontext( "cn=Collective Subentry", subentry );
// create real enty
Attributes attributes = this.getPersonAttributes( "Bush", "Kate Bush" );
aaCtx.createSubcontext( "cn=Kate Bush", attributes );
// search
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setReturningAttributes( new String[]
{ "c-l" } );
NamingEnumeration<SearchResult> res = aaCtx.search( "", "(cn=Kate Bush)", controls );
assertTrue( res.hasMore() );
SearchResult result = res.next();
// ensure that result is not null
assertNotNull( result );
Attributes attrs = result.getAttributes();
// ensure the one and only attribute is "c-l"
assertEquals( 1, attrs.size() );
assertNotNull( attrs.get( "c-l" ) );
assertEquals( 1, attrs.get( "c-l" ).size() );
assertEquals( "Munich", ( String ) attrs.get( "c-l" ).get() );
}
@Test
public void testSearchUsersAttrs() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setReturningAttributes( new String[]
{ "*" } );
NamingEnumeration<SearchResult> res = ctx.search( "", "(commonName=Tori Amos)", controls );
assertTrue( res.hasMore() );
SearchResult result = res.next();
// ensure that result is not null
assertNotNull( result );
Attributes attrs = result.getAttributes();
// ensure that all user attributes are returned
assertEquals( 6, attrs.size() );
assertNotNull( attrs.get( "cn" ) );
assertNotNull( attrs.get( "sn" ) );
assertNotNull( attrs.get( "objectClass" ) );
assertNotNull( attrs.get( "jpegPhoto" ) );
assertNotNull( attrs.get( "description" ) );
assertNotNull( attrs.get( "userCertificate" ) );
assertNull( attrs.get( "createtimestamp" ) );
assertNull( attrs.get( "creatorsname" ) );
}
@Test
public void testSearchOperationalAttrs() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setReturningAttributes( new String[]
{ "+" } );
NamingEnumeration<SearchResult> res = ctx.search( "", "(commonName=Tori Amos)", controls );
assertTrue( res.hasMore() );
SearchResult result = res.next();
// ensure that result is not null
assertNotNull( result );
Attributes attrs = result.getAttributes();
// ensure that all operational attributes are returned
// and no user attributes
assertEquals( 4, attrs.size() );
assertNull( attrs.get( "cn" ) );
assertNull( attrs.get( "sn" ) );
assertNull( attrs.get( "objectClass" ) );
assertNull( attrs.get( "jpegPhoto" ) );
assertNull( attrs.get( "description" ) );
assertNotNull( attrs.get( "createtimestamp" ) );
assertNotNull( attrs.get( "creatorsname" ) );
assertNotNull( attrs.get( "entryuuid" ) );
assertNotNull( attrs.get( "entrycsn" ) );
}
@Test
public void testSearchAllAttrs() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setReturningAttributes( new String[]
{ "+", "*" } );
NamingEnumeration<SearchResult> res = ctx.search( "", "(commonName=Tori Amos)", controls );
assertTrue( res.hasMore() );
SearchResult result = ( SearchResult ) res.next();
// ensure that result is not null
assertNotNull( result );
Attributes attrs = result.getAttributes();
// ensure that all user attributes are returned
assertEquals( 10, attrs.size() );
assertNotNull( attrs.get( "cn" ) );
assertNotNull( attrs.get( "sn" ) );
assertNotNull( attrs.get( "objectClass" ) );
assertNotNull( attrs.get( "jpegPhoto" ) );
assertNotNull( attrs.get( "userCertificate" ) );
assertNotNull( attrs.get( "description" ) );
assertNotNull( attrs.get( "createtimestamp" ) );
assertNotNull( attrs.get( "creatorsname" ) );
assertNotNull( attrs.get( "entryuuid" ) );
assertNotNull( attrs.get( "entrycsn" ) );
}
@Test
public void testSearchBadDN() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
try
{
ctx.search( "cn=admin", "(objectClass=*)", controls );
}
catch ( NameNotFoundException nnfe )
{
assertTrue( true );
}
}
@Test
public void testSearchInvalidDN() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
try
{
ctx.search( "myBadDN", "(objectClass=*)", controls );
fail();
}
catch ( NamingException ne )
{
assertTrue( true );
}
}
/**
* Check if operational attributes are present, if "+" is requested.
*/
@Test
public void testSearchOperationalAttributes() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls ctls = new SearchControls();
ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
ctls.setReturningAttributes( new String[]
{ "+" } );
NamingEnumeration<SearchResult> result = ctx.search( HEATHER_RDN, FILTER, ctls );
if ( result.hasMore() )
{
SearchResult entry = result.next();
String[] opAttrNames =
{ "creatorsName", "createTimestamp" };
checkForAttributes( entry.getAttributes(), opAttrNames );
}
else
{
fail( "entry " + HEATHER_RDN + " not found" );
}
result.close();
}
/**
* Check if user attributes are present, if "*" is requested.
*/
@Test
public void testSearchUserAttributes() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls ctls = new SearchControls();
ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
ctls.setReturningAttributes( new String[]
{ "*" } );
NamingEnumeration<SearchResult> result = ctx.search( HEATHER_RDN, FILTER, ctls );
if ( result.hasMore() )
{
SearchResult entry = result.next();
String[] userAttrNames =
{ "objectClass", "sn", "cn" };
checkForAttributes( entry.getAttributes(), userAttrNames );
}
else
{
fail( "entry " + HEATHER_RDN + " not found" );
}
result.close();
}
/**
* Check if no error occurs if " " is requested.
*/
@Test
public void testSearchUserAttributes_Space() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls ctls = new SearchControls();
ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
ctls.setReturningAttributes( new String[]
{ " " } );
NamingEnumeration<SearchResult> result = ctx.search( HEATHER_RDN, FILTER, ctls );
result.close();
}
/**
* Check if no error occurs if "" is requested.
*/
@Test
public void testSearchUserAttributes_EmptyAttrs() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls ctls = new SearchControls();
ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
ctls.setReturningAttributes( new String[]
{ "" } );
NamingEnumeration<SearchResult> result = ctx.search( HEATHER_RDN, FILTER, ctls );
result.close();
}
/**
* Check if no error occurs if "" is requested.
*/
@Test
public void testSearchUserAttributes_NullAttrs() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls ctls = new SearchControls();
ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
ctls.setReturningAttributes( new String[0] );
NamingEnumeration<SearchResult> result = ctx.search( HEATHER_RDN, FILTER, ctls );
result.close();
}
/**
* Check if user and operational attributes are present, if both "*" and "+" are requested.
*/
@Test
public void testSearchOperationalAndUserAttributes() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls ctls = new SearchControls();
ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
ctls.setReturningAttributes( new String[]
{ "+", "*" } );
String[] userAttrNames =
{ "objectClass", "sn", "cn" };
String[] opAttrNames =
{ "creatorsName", "createTimestamp" };
NamingEnumeration<SearchResult> result = ctx.search( HEATHER_RDN, FILTER, ctls );
if ( result.hasMore() )
{
SearchResult entry = result.next();
Attributes attrs = entry.getAttributes();
assertNotNull( attrs );
checkForAttributes( attrs, userAttrNames );
checkForAttributes( attrs, opAttrNames );
}
else
{
fail( "entry " + HEATHER_RDN + " not found" );
}
result.close();
ctls.setReturningAttributes( new String[]
{ "*", "+" } );
result = ctx.search( HEATHER_RDN, FILTER, ctls );
if ( result.hasMore() )
{
SearchResult entry = ( SearchResult ) result.next();
Attributes attrs = entry.getAttributes();
assertNotNull( attrs );
checkForAttributes( attrs, userAttrNames );
checkForAttributes( attrs, opAttrNames );
}
else
{
fail( "entry " + HEATHER_RDN + " not found" );
}
result.close();
}
@Test
public void testSubstringSearchWithEscapedCharsInFilter() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
Attributes attrs = new BasicAttributes( "objectClass", "inetOrgPerson", true );
attrs.get( "objectClass" ).add( "organizationalPerson" );
attrs.get( "objectClass" ).add( "person" );
attrs.put( "givenName", "Jim" );
attrs.put( "sn", "Bean" );
attrs.put( "cn", "jimbean" );
attrs.put( "description", "(sex*pis\\tols)" );
ctx.createSubcontext( "cn=jimbean", attrs );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setReturningAttributes( new String[]
{ "cn" } );
String[] filters = new String[]
{ "(description=*\\28*)", "(description=*\\29*)", "(description=*\\2A*)", "(description=*\\5C*)" };
for ( String filter : filters )
{
NamingEnumeration<SearchResult> res = ctx.search( "", filter, controls );
assertTrue( res.hasMore() );
SearchResult result = res.next();
assertNotNull( result );
attrs = result.getAttributes();
assertEquals( 1, attrs.size() );
assertNotNull( attrs.get( "cn" ) );
assertEquals( 1, attrs.get( "cn" ).size() );
assertEquals( "jimbean", ( String ) attrs.get( "cn" ).get() );
assertFalse( res.hasMore() );
}
}
/**
* Test for DIRSERVER-1180 where search hangs when an invalid a substring
* expression missing an any field is used in a filter: i.e. (cn=**).
*
* @see https://issues.apache.org/jira/browse/DIRSERVER-1180
*/
@Test
public void testMissingAnyInSubstring_DIRSERVER_1180() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
Attributes attrs = new BasicAttributes( "objectClass", "inetOrgPerson", true );
attrs.get( "objectClass" ).add( "organizationalPerson" );
attrs.get( "objectClass" ).add( "person" );
attrs.put( "givenName", "Jim" );
attrs.put( "sn", "Bean" );
attrs.put( "cn", "jimbean" );
ctx.createSubcontext( "cn=jimbean", attrs );
try
{
ctx.search( "", "(cn=**)", new SearchControls() );
fail();
}
catch ( Exception e )
{
assertTrue( true );
}
}
@Test
public void testSubstringSearchWithEscapedAsterisksInFilter_DIRSERVER_1181() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
Attributes vicious = new BasicAttributes( true );
Attribute ocls = new BasicAttribute( "objectClass" );
ocls.add( "top" );
ocls.add( "person" );
vicious.put( ocls );
vicious.put( "cn", "x*y*z*" );
vicious.put( "sn", "x*y*z*" );
ctx.createSubcontext( "cn=x*y*z*", vicious );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
controls.setReturningAttributes( new String[]
{ "cn" } );
NamingEnumeration<SearchResult> res;
res = ctx.search( "", "(cn=*x\\2Ay\\2Az\\2A*)", controls );
assertTrue( res.hasMore() );
assertEquals( "x*y*z*", res.next().getAttributes().get( "cn" ).get() );
assertFalse( res.hasMore() );
res = ctx.search( "", "(cn=*{0}*)", new String[]
{ "x*y*z*" }, controls );
assertTrue( res.hasMore() );
assertEquals( "x*y*z*", res.next().getAttributes().get( "cn" ).get() );
assertFalse( res.hasMore() );
}
/**
* Test for DIRSERVER-1347: Unicode characters in filter value.
*/
@Test
public void testUnicodeFilter_DIRSERVER_1347() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
Attributes groupOfNames = new BasicAttributes( true );
Attribute groupOfNamesOC = new BasicAttribute( "objectClass" );
groupOfNamesOC.add( "top" );
groupOfNamesOC.add( "groupOfNames" );
groupOfNames.put( groupOfNamesOC );
groupOfNames.put( "cn", "groupOfNames" );
Attribute member = new BasicAttribute( "member" );
member.add( "uid=test,ou=system" );
member.add( "uid=r\u00e9dacteur1,ou=system" );
groupOfNames.put( member );
ctx.createSubcontext( "cn=groupOfNames", groupOfNames );
Attributes groupOfUniqueNames = new BasicAttributes( true );
Attribute groupOfUniqueNamesOC = new BasicAttribute( "objectClass" );
groupOfUniqueNamesOC.add( "top" );
groupOfUniqueNamesOC.add( "groupOfUniqueNames" );
groupOfUniqueNames.put( groupOfUniqueNamesOC );
groupOfUniqueNames.put( "cn", "groupOfUniqueNames" );
Attribute uniqueMember = new BasicAttribute( "uniqueMember" );
uniqueMember.add( "uid=test,ou=system" );
uniqueMember.add( "uid=r\u00e9dacteur1,ou=system" );
groupOfUniqueNames.put( uniqueMember );
ctx.createSubcontext( "cn=groupOfUniqueNames", groupOfUniqueNames );
SearchControls controls = new SearchControls();
NamingEnumeration<SearchResult> res;
// search with unicode filter value
res = ctx.search( "", "(member=uid=r\u00e9dacteur1,ou=system)", controls );
assertTrue( res.hasMore() );
assertEquals( "groupOfNames", res.next().getAttributes().get( "cn" ).get() );
assertFalse( res.hasMore() );
// search with escaped filter value
res = ctx.search( "", "(member=uid=r\\c3\\a9dacteur1,ou=system)", controls );
assertTrue( res.hasMore() );
assertEquals( "groupOfNames", res.next().getAttributes().get( "cn" ).get() );
assertFalse( res.hasMore() );
// search with unicode filter value
res = ctx.search( "", "(uniqueMember=uid=r\u00e9dacteur1,ou=system)", controls );
assertTrue( res.hasMore() );
assertEquals( "groupOfUniqueNames", res.next().getAttributes().get( "cn" ).get() );
assertFalse( res.hasMore() );
// search with escaped filter value
res = ctx.search( "", "(uniqueMember=uid=r\\c3\\a9dacteur1,ou=system)", controls );
assertTrue( res.hasMore() );
assertEquals( "groupOfUniqueNames", res.next().getAttributes().get( "cn" ).get() );
assertFalse( res.hasMore() );
}
/**
* Check if no user attributes are present, if "1.1" is requested.
*/
@Test
public void testSearchUserAttributes_1_1() throws Exception
{
LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer ).lookup( BASE );
SearchControls ctls = new SearchControls();
ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
ctls.setReturningAttributes( new String[]
{ "1.1" } );
NamingEnumeration<SearchResult> result = ctx.search( HEATHER_RDN, FILTER, ctls );
if ( result.hasMore() )
{
SearchResult entry = result.next();
assertEquals( "No user attributes expected when requesting attribute 1.1", 0, entry.getAttributes().size() );
}
else
{
fail( "entry " + HEATHER_RDN + " not found" );
}
result.close();
}
/**
* test an abandonned search request.
*/
@Test
public void testAbandonnedRequest() throws Exception
{
LdapConnection asyncCnx = new LdapNetworkConnection( "localhost", ldapServer.getPort() );
try
{
// Use the client API as JNDI cannot be used to do a search without
// first binding. (hmmm, even client API won't allow searching without binding)
asyncCnx.bind( "uid=admin,ou=system", "secret" );
// First, add 1000 entries in the server
for ( int i = 0; i < 1000; i++ )
{
String dn = "cn=user" + i + "," + BASE;
Entry kate = new DefaultEntry( new Dn( dn ) );
kate.add( "objectclass", "top", "person" );
kate.add( "sn", "Bush" );
kate.add( "cn", "user" + i );
asyncCnx.add( kate );
}
// Searches for all the entries in ou=system
Cursor<Response> cursor = asyncCnx.search( "ou=system", "(ObjectClass=*)", SearchScope.SUBTREE, "*" );
// Now loop on all the elements found, and abandon after 10 elements returned
int count = 0;
while ( cursor.next() )
{
count++;
if ( count == 10 )
{
// the message ID = 1 bind op + 1000 add ops + 1 search op
asyncCnx.abandon( 1002 );
}
}
assertEquals( 10, count );
}
catch ( LdapException e )
{
e.printStackTrace();
fail( "Should not have caught exception." );
}
finally
{
asyncCnx.unBind();
}
}
@Test
public void testSearchSubstringWithPlus() throws Exception
{
LdapContext ctx = getWiredContext( ldapServer );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
controls.setTimeLimit( 10 );
NamingEnumeration<SearchResult> result = ctx.search( "ou=system", "(description=*+*)", controls );
assertTrue( result.hasMore() );
SearchResult entry = result.next();
assertEquals( "Kim Wilde", entry.getAttributes().get( "cn" ).get() );
}
@Test
public void testSearchSizeLimit() throws Exception
{
long sizeLimit = 7;
LdapConnection connection = getClientApiConnection( ldapServer );
SearchRequest req = new org.apache.directory.shared.ldap.model.message.SearchRequestImpl();
req.setBase( new Dn( "ou=system" ) );
req.setFilter( "(ou=*)" );
req.setScope( SearchScope.SUBTREE );
req.setSizeLimit( sizeLimit );
Cursor<Response> cursor = connection.search( req );
long i = 0;
while ( cursor.next() )
{
++i;
}
assertEquals( sizeLimit, i );
}
@Test
@Ignore("This test is failing because of the timing issue. Note that the SearchHandler handles time based searches correctly, this is just the below test's problem")
public void testSearchTimeLimit() throws Exception, InterruptedException
{
LdapConnection connection = getClientApiConnection( ldapServer );
SearchRequest req = new SearchRequestImpl();
req.setBase( new Dn( "ou=schema" ) );
req.setFilter( "(objectClass=*)" );
req.setScope( SearchScope.SUBTREE );
Cursor<Response> cursor = connection.search( req );
int count = 0;
while ( cursor.next() )
{
++count;
}
cursor.close();
req.setTimeLimit( 1 );
cursor = connection.search( req );
int newCount = 0;
while ( cursor.next() )
{
++newCount;
}
assertTrue( newCount < count );
}
@Test
public void testSearchComplexFilter() throws Exception
{
LdapContext ctx = getWiredContext( ldapServer );
SearchControls controls = new SearchControls();
controls.setSearchScope( SearchControls.OBJECT_SCOPE );
controls.setTimeLimit( 10 );
NamingEnumeration<SearchResult> result = ctx.search( "cn=Kim Wilde,ou=system",
"(&(&(ObjectClass=person)(!(ObjectClass=strongAuthenticationUser))(sn=Wilde)))", controls );
assertTrue( result.hasMore() );
SearchResult sr = result.next();
assertNotNull( sr );
assertEquals( "Kim Wilde", sr.getAttributes().get( "cn" ).get() );
// Now check with another version of the filter
result = ctx.search( "cn=Kim Wilde,ou=system",
"(&(sn=Wilde)(&(objectClass=person)(!(objectClass=strongAuthenticationUser))))", controls );
assertTrue( result.hasMore() );
sr = result.next();
assertNotNull( sr );
assertEquals( "Kim Wilde", sr.getAttributes().get( "cn" ).get() );
}
}