/* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.tools.ldapdecoder.protocol; import java.io.PrintStream; import java.util.Date; import com.slamd.asn1.ASN1Boolean; import com.slamd.asn1.ASN1Element; import com.slamd.asn1.ASN1Enumerated; import com.slamd.asn1.ASN1Integer; import com.slamd.asn1.ASN1OctetString; import com.slamd.asn1.ASN1Sequence; /** * This class defines an LDAP search request, which is used to locate entries * in the directory server. * * * @author Neil A. Wilson */ public class SearchRequest extends ProtocolOp { /** * The search scope that indicates that only the base object will be * evaluated. */ public static final int SCOPE_BASE_OBJECT = 0; /** * The search scope that indicates that only entries exactly one level below * the search base will be evaluated. */ public static final int SCOPE_SINGLE_LEVEL = 1; /** * The search scope that indicates that the base object and all entries below * it will be evaluated. */ public static final int SCOPE_WHOLE_SUBTREE = 2; /** * The search scope that indicates that all entries below the base object (but * not the base entry itself) will be evaluated. */ public static final int SCOPE_SUBORDINATE_SUBTREE = 3; /** * The alias policy that indicates that aliases should never be dereferenced. */ public static final int DEREF_NEVER = 0; /** * The alias policy that indicates that any aliases found when performing the * search should be dereferenced. */ public static final int DEREF_IN_SEARCHING = 1; /** * The alias policy that indicates that the search base should be dereferenced * if it is an alias. */ public static final int DEREF_FINDING_BASE_OBJECT = 2; /** * The alias policy that indicates that all aliases encountered should be * dereferenced. */ public static final int DEREF_ALWAYS = 3; // Indicates whether to include only the attribute types and no values in the // matching entries. private boolean typesOnly; // The policy that should be used for handling aliases encountered while // searching. private int derefPolicy; // The scope to use for the search. private int scope; // The maximum number of entries that should be returned from the search. private int sizeLimit; // The maximum length of time that should be spent processing the search. private int timeLimit; // The search filter that specifies the criteria for finding entries. private SearchFilter filter; // The base DN to use for the search. private String baseDN; // The list of attributes that should be included in matching entries. private String[] attributes; /** * Creates a new search filter with the provided information. * * @param baseDN The base DN to use for the search. * @param scope The scope to use for the search. * @param derefPolicy The policy to use when handling aliases encountered * while searching. * @param sizeLimit The size limit to use for the search. * @param timeLimit The time limit to use for the search. * @param typesOnly Indicates whether to include only attribute type and * no values in the matching entries. * @param filter The filter to use for the search. * @param attributes The list of attributes to include in matching entries. */ public SearchRequest(String baseDN, int scope, int derefPolicy, int sizeLimit, int timeLimit, boolean typesOnly, SearchFilter filter, String[] attributes) { this.baseDN = baseDN; this.scope = scope; this.derefPolicy = derefPolicy; this.sizeLimit = sizeLimit; this.timeLimit = timeLimit; this.typesOnly = typesOnly; this.filter = filter; this.attributes = attributes; } /** * Retrieves the base DN to use for the search. * * @return The base DN to use for the search. */ public String getBaseDN() { return baseDN; } /** * Retrieves the scope to use for the search. * * @return The scope to use for the search. */ public int getScope() { return scope; } /** * Retrieves the alias dereferencing policy for the search. * * @return The alias dereferencing policy for the search. */ public int getDerefPolicy() { return derefPolicy; } /** * Retrieves the size limit to use for the search. * * @return The size limit to use for the search. */ public int getSizeLimit() { return sizeLimit; } /** * Retrieves the time limit to use for the search. * * @return The time limit to use for the search. */ public int getTimeLimit() { return timeLimit; } /** * Indicates whether only attribute types and no values should be included in * matching entries. * * @return <CODE>true</CODE> if only attribute types and no values should be * included in matching entries, or <CODE>false</CODE> if not. */ public boolean getTypesOnly() { return typesOnly; } /** * Retrieves the filter to use for the search. * * @return The filter to use for the search. */ public SearchFilter getFilter() { return filter; } /** * Retrieves the set of attributes that should be included in matching * entries. * * @return The set of attributes that should be included in matching entries. */ public String[] getAttributes() { return attributes; } /** * Encodes this protocol op to an ASN.1 element. * * @return The ASN.1 element containing the encoded protocol op. */ public ASN1Element encode() { ASN1Element attrSequence; if ((attributes == null) || (attributes.length == 0)) { attrSequence = new ASN1Sequence(); } else { ASN1Element[] elements = new ASN1Element[attributes.length]; for (int i=0; i < elements.length; i++) { elements[i] = new ASN1OctetString(attributes[i]); } attrSequence = new ASN1Sequence(elements); } ASN1Element[] searchElements = new ASN1Element[] { new ASN1OctetString(baseDN), new ASN1Enumerated(scope), new ASN1Enumerated(derefPolicy), new ASN1Integer(sizeLimit), new ASN1Integer(timeLimit), new ASN1Boolean(typesOnly), filter.encode(), attrSequence }; return new ASN1Sequence(SEARCH_REQUEST_TYPE, searchElements); } /** * Decodes the provided ASN.1 element as a search request protocol op. * * @param element The ASN.1 element to be decoded. * * @return The decoded search request. * * @throws ProtocolException If a problem occurs while decoding the provided * ASN.1 element as a search request. */ public static SearchRequest decodeSearchRequest(ASN1Element element) throws ProtocolException { ASN1Element[] searchElements; try { searchElements = element.decodeAsSequence().getElements(); } catch (Exception e) { throw new ProtocolException("Unable to decode search request sequence", e); } if (searchElements.length != 8) { throw new ProtocolException("There must be exactly eight elements in a " + "search request sequence"); } String baseDN; try { baseDN = searchElements[0].decodeAsOctetString().getStringValue(); } catch (Exception e) { throw new ProtocolException("Unable to decode search request base DN", e); } int scope; try { scope = searchElements[1].decodeAsEnumerated().getIntValue(); } catch (Exception e) { throw new ProtocolException("Unable to decode search request scope", e); } int derefPolicy; try { derefPolicy = searchElements[2].decodeAsEnumerated().getIntValue(); } catch (Exception e) { throw new ProtocolException("Unable to decode search request alias " + "dereferencing policy", e); } int sizeLimit; try { sizeLimit = searchElements[3].decodeAsInteger().getIntValue(); } catch (Exception e) { throw new ProtocolException("Unable to decode search request size limit", e); } int timeLimit; try { timeLimit = searchElements[4].decodeAsInteger().getIntValue(); } catch (Exception e) { throw new ProtocolException("Unable to decode search request time limit", e); } boolean typesOnly; try { typesOnly = searchElements[5].decodeAsBoolean().getBooleanValue(); } catch (Exception e) { throw new ProtocolException("Unable to decode search request typesOnly", e); } SearchFilter filter = SearchFilter.decode(searchElements[6]); String[] attributes; try { ASN1Element[] attrElements = searchElements[7].decodeAsSequence().getElements(); attributes = new String[attrElements.length]; for (int i=0; i < attrElements.length; i++) { attributes[i] = attrElements[i].decodeAsOctetString().getStringValue(); } } catch (Exception e) { throw new ProtocolException("Unable to decode search request attribute " + "list", e); } return new SearchRequest(baseDN, scope, derefPolicy, sizeLimit, timeLimit, typesOnly, filter, attributes); } /** * Retrieves a user-friendly name for this protocol op. * * @return A user-friendly name for this protocol op. */ public String getProtocolOpType() { return "LDAP Search Request"; } /** * Retrieves a string representation of this protocol op with the specified * indent. * * @param indent The number of spaces to indent the output. * * @return A string representation of this protocol op with the specified * indent. */ public String toString(int indent) { StringBuilder indentBuf = new StringBuilder(indent); for (int i=0; i < indent; i++) { indentBuf.append(' '); } StringBuilder buffer = new StringBuilder(); buffer.append(indentBuf).append("Base DN: "). append(baseDN).append(LDAPMessage.EOL); String scopeStr; switch (scope) { case SCOPE_BASE_OBJECT: scopeStr = " (baseObject)"; break; case SCOPE_SINGLE_LEVEL: scopeStr = " (singleLevel)"; break; case SCOPE_WHOLE_SUBTREE: scopeStr = " (wholeSubtree)"; break; case SCOPE_SUBORDINATE_SUBTREE: scopeStr = " (subordinateSubtree)"; break; default: scopeStr =" (Invalid Search Scope)"; break; } buffer.append(indentBuf).append("Scope: ").append(scope). append(scopeStr).append(LDAPMessage.EOL); String derefStr; switch (derefPolicy) { case DEREF_NEVER: derefStr = " (neverDerefAliases)"; break; case DEREF_IN_SEARCHING: derefStr = " (derefInSearching)"; break; case DEREF_FINDING_BASE_OBJECT: derefStr = " (derefFindingBaseObj)"; break; case DEREF_ALWAYS: derefStr = " (derefAlways)"; break; default: derefStr = " (Invalid Dereferencing Policy)"; break; } buffer.append(indentBuf).append("Deref Aliases: ").append(derefPolicy). append(derefStr).append(LDAPMessage.EOL); buffer.append(indentBuf).append("Size Limit: ").append(sizeLimit). append(LDAPMessage.EOL); buffer.append(indentBuf).append("Time Limit: ").append(timeLimit). append(LDAPMessage.EOL); buffer.append(indentBuf).append("Types Only: ").append(typesOnly). append(LDAPMessage.EOL); buffer.append(indentBuf).append("Filter: "); filter.toStringBuilder(buffer); buffer.append(LDAPMessage.EOL); buffer.append(indentBuf).append("Attributes:").append(LDAPMessage.EOL); for (int i=0; ((attributes != null) && (i < attributes.length)); i++) { buffer.append(indentBuf).append(" ").append(attributes[i]). append(LDAPMessage.EOL); } return buffer.toString(); } /** * Constructs a string representation of this LDAP message in a form that can * be written to a SLAMD script. It may be empty if this message isn't one * that would be generated as part of a client request. * * @param scriptWriter The print stream to which the script contents should * be written. */ public void toSLAMDScript(PrintStream scriptWriter) { scriptWriter.println("#### Search request captured at " + new Date()); scriptWriter.println("# Search Base: " + baseDN); String scopeStr = String.valueOf(scope); switch(scope) { case SCOPE_BASE_OBJECT: scriptWriter.println("# Scope: baseObject"); scopeStr = "conn.scopeBase()"; break; case SCOPE_SINGLE_LEVEL: scriptWriter.println("# Scope: singleLevel"); scopeStr = "conn.scopeOne()"; break; case SCOPE_WHOLE_SUBTREE: scriptWriter.println("# Scope: wholeSubtree"); scopeStr = "conn.scopeSub()"; break; } switch (derefPolicy) { case DEREF_NEVER: scriptWriter.println("# Deref Policy: neverDerefAliases"); break; case DEREF_IN_SEARCHING: scriptWriter.println("# Deref Policy: derefInSearching"); break; case DEREF_FINDING_BASE_OBJECT: scriptWriter.println("# Deref Policy: derefFindingBaseObj"); break; case DEREF_ALWAYS: scriptWriter.println("# Deref Policy: derefAlways"); break; } scriptWriter.println("# Size Limit: " + sizeLimit); scriptWriter.println("# Time Limit: " + timeLimit); scriptWriter.println("# Types Only: " + typesOnly); String filterString = filter.toString(); scriptWriter.println("# Filter: " + filterString); if ((attributes != null) && (attributes.length > 0)) { scriptWriter.println("# Attributes to Return:"); for (int i=0; i < attributes.length; i++) { scriptWriter.println("# " + attributes[i]); } } scriptWriter.println("searchAttrs.removeAll();"); if ((attributes != null) && (attributes.length > 0)) { for (int i=0; i < attributes.length; i++) { scriptWriter.println("searchAttrs.addValue(\"" + attributes[i] + "\");"); } } scriptWriter.println("resultCode = conn.search(\"" + baseDN + "\", " + scopeStr + ", \"" + filterString + "\", searchAttrs, " + timeLimit + ", " + sizeLimit + ");"); scriptWriter.println(); scriptWriter.println(); } }