Lines 17-36
Link Here
|
17 |
|
17 |
|
18 |
package org.apache.jmeter.protocol.ldap.sampler; |
18 |
package org.apache.jmeter.protocol.ldap.sampler; |
19 |
|
19 |
|
20 |
import java.util.Hashtable; |
20 |
import java.util.*; |
21 |
import java.util.Iterator; |
21 |
import java.io.UnsupportedEncodingException; |
22 |
import java.util.Map; |
|
|
23 |
|
22 |
|
24 |
import javax.naming.NamingEnumeration; |
23 |
import javax.naming.NamingEnumeration; |
25 |
import javax.naming.NamingException; |
24 |
import javax.naming.NamingException; |
26 |
import javax.naming.directory.Attribute; |
25 |
import javax.naming.directory.*; |
27 |
import javax.naming.directory.Attributes; |
|
|
28 |
import javax.naming.directory.BasicAttribute; |
29 |
import javax.naming.directory.BasicAttributes; |
30 |
import javax.naming.directory.DirContext; |
31 |
import javax.naming.directory.InitialDirContext; |
32 |
import javax.naming.directory.ModificationItem; |
33 |
import javax.naming.directory.SearchResult; |
34 |
|
26 |
|
35 |
import org.apache.jmeter.config.Argument; |
27 |
import org.apache.jmeter.config.Argument; |
36 |
import org.apache.jmeter.config.Arguments; |
28 |
import org.apache.jmeter.config.Arguments; |
Lines 44-49
Link Here
|
44 |
import org.apache.jmeter.testelement.property.PropertyIterator; |
36 |
import org.apache.jmeter.testelement.property.PropertyIterator; |
45 |
import org.apache.jmeter.testelement.property.StringProperty; |
37 |
import org.apache.jmeter.testelement.property.StringProperty; |
46 |
import org.apache.jmeter.testelement.property.TestElementProperty; |
38 |
import org.apache.jmeter.testelement.property.TestElementProperty; |
|
|
39 |
import org.apache.jmeter.util.JMeterUtils; |
47 |
import org.apache.jorphan.logging.LoggingManager; |
40 |
import org.apache.jorphan.logging.LoggingManager; |
48 |
import org.apache.log.Logger; |
41 |
import org.apache.log.Logger; |
49 |
|
42 |
|
Lines 56-61
Link Here
|
56 |
|
49 |
|
57 |
private static final Logger log = LoggingManager.getLoggerForClass(); |
50 |
private static final Logger log = LoggingManager.getLoggerForClass(); |
58 |
|
51 |
|
|
|
52 |
/** Signature start of response data generated by this sample. */ |
53 |
public static final String LDAPANSWER = "<ldapanswer>"; |
54 |
public static final String LDAPANSWER_END = LDAPANSWER.replaceFirst("<", "</"); |
55 |
|
59 |
public final static String SERVERNAME = "servername"; // $NON-NLS-1$ |
56 |
public final static String SERVERNAME = "servername"; // $NON-NLS-1$ |
60 |
|
57 |
|
61 |
public final static String PORT = "port"; // $NON-NLS-1$ |
58 |
public final static String PORT = "port"; // $NON-NLS-1$ |
Lines 125-139
Link Here
|
125 |
// TODO replace these with ThreadLocal |
122 |
// TODO replace these with ThreadLocal |
126 |
private static Hashtable ldapConnections = new Hashtable(); |
123 |
private static Hashtable ldapConnections = new Hashtable(); |
127 |
|
124 |
|
128 |
private static Hashtable ldapContexts = new Hashtable(); |
125 |
private static Hashtable ldapContexts = new Hashtable(); |
|
|
126 |
protected static final int MAX_SORTED_RESULTS = JMeterUtils.getPropDefault("ldapsampler.max_sorted_results", 1000); |
127 |
public static final String OBJECT_SCOPE_STR = "object"; |
128 |
public static final String ONELEVEL_SCOPE_STR = "onelevel"; |
129 |
public static final String SUBTREE_SCOPE_STR = "subtree"; |
129 |
|
130 |
|
130 |
/*************************************************************************** |
|
|
131 |
* !ToDo (Constructor description) |
132 |
**************************************************************************/ |
133 |
public LDAPExtSampler() { |
134 |
} |
135 |
|
131 |
|
136 |
/*************************************************************************** |
132 |
/*************************************************************************** |
|
|
133 |
* !ToDo (Constructor description) |
134 |
**************************************************************************/ |
135 |
public LDAPExtSampler() { |
136 |
} |
137 |
|
138 |
/*************************************************************************** |
137 |
* Gets the username attribute of the LDAP object |
139 |
* Gets the username attribute of the LDAP object |
138 |
* |
140 |
* |
139 |
* @return The username |
141 |
* @return The username |
Lines 511-517
Link Here
|
511 |
if ("add".equals(item.getOpcode())) { // $NON-NLS-1$ |
513 |
if ("add".equals(item.getOpcode())) { // $NON-NLS-1$ |
512 |
mods[count] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr); |
514 |
mods[count] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr); |
513 |
} else { |
515 |
} else { |
514 |
if ("delete".equals(item.getOpcode())) { // $NON-NLS-1$ |
516 |
if ("delete".equals(item.getOpcode()) || "remove".equals(item.getOpcode())) { // $NON-NLS-1$ |
515 |
mods[count] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr); |
517 |
mods[count] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr); |
516 |
} else { |
518 |
} else { |
517 |
mods[count] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr); |
519 |
mods[count] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr); |
Lines 681-687
Link Here
|
681 |
* @return !ToDo (Return description) |
683 |
* @return !ToDo (Return description) |
682 |
**************************************************************************/ |
684 |
**************************************************************************/ |
683 |
public SampleResult sample(Entry e) { |
685 |
public SampleResult sample(Entry e) { |
684 |
String responseData = "<ldapanswer>"; |
686 |
String responseData = LDAPANSWER; |
685 |
SampleResult res = new SampleResult(); |
687 |
SampleResult res = new SampleResult(); |
686 |
res.setResponseData("successfull".getBytes()); |
688 |
res.setResponseData("successfull".getBytes()); |
687 |
res.setResponseMessage("Success"); |
689 |
res.setResponseMessage("Success"); |
Lines 761-799
Link Here
|
761 |
responseData = responseData + "<newdn>" + getPropertyAsString(NEWDN) + "</newdn></operation>"; |
763 |
responseData = responseData + "<newdn>" + getPropertyAsString(NEWDN) + "</newdn></operation>"; |
762 |
renameTest(temp_client, dirContext, res); |
764 |
renameTest(temp_client, dirContext, res); |
763 |
} else if (getPropertyAsString(TEST).equals(SEARCHBASE)) { |
765 |
} else if (getPropertyAsString(TEST).equals(SEARCHBASE)) { |
764 |
res.setSamplerData("Search with filter " + getPropertyAsString(SEARCHFILTER)); |
766 |
final StringBuffer sb = new StringBuffer(2 * 1024); |
765 |
responseData = responseData + "<operation><opertype>search</opertype>"; |
767 |
final String scopeStr = getPropertyAsString(SCOPE); |
766 |
responseData = responseData + "<searchfilter>" + getPropertyAsString(SEARCHFILTER) + "</searchfilter>"; |
768 |
final int scope; |
767 |
responseData = responseData + "<searchbase>" + getPropertyAsString(SEARCHBASE) + "," |
769 |
|
768 |
+ getPropertyAsString(ROOTDN) + "</searchbase>"; |
770 |
res.setSamplerData("Search with filter " + getPropertyAsString(SEARCHFILTER)); |
769 |
responseData = responseData + "<scope>" + getPropertyAsString(SCOPE) + "</scope>"; |
771 |
sb.append(responseData); |
770 |
responseData = responseData + "<countlimit>" + getPropertyAsString(COUNTLIM) + "</countlimit>"; |
772 |
sb.append("<operation>"); |
771 |
responseData = responseData + "<timelimit>" + getPropertyAsString(TIMELIM) + "</timelimit>"; |
773 |
writeSearchResponseHeader(sb); |
772 |
responseData = responseData + "</operation><searchresult>"; |
774 |
if (OBJECT_SCOPE_STR.equals(scopeStr)) |
|
|
775 |
scope = SearchControls.OBJECT_SCOPE; |
776 |
else if (ONELEVEL_SCOPE_STR.equals(scopeStr)) |
777 |
scope = SearchControls.ONELEVEL_SCOPE; |
778 |
else if (SUBTREE_SCOPE_STR.equals(scopeStr)) |
779 |
scope = SearchControls.SUBTREE_SCOPE; |
780 |
else |
781 |
// for backwards compatibility |
782 |
scope = getPropertyAsInt(SCOPE); |
783 |
|
773 |
res.sampleStart(); |
784 |
res.sampleStart(); |
774 |
NamingEnumeration srch = temp_client.searchTest(dirContext, getPropertyAsString(SEARCHBASE), getPropertyAsString(SEARCHFILTER), |
785 |
NamingEnumeration srch = temp_client.searchTest(dirContext, getPropertyAsString(SEARCHBASE), getPropertyAsString(SEARCHFILTER), |
775 |
getPropertyAsInt(SCOPE), getPropertyAsLong(COUNTLIM), getPropertyAsInt(TIMELIM), |
786 |
scope, getPropertyAsLong(COUNTLIM), getPropertyAsInt(TIMELIM), |
776 |
getRequestAttributes(getPropertyAsString(ATTRIBS)), getPropertyAsBoolean(RETOBJ), |
787 |
getRequestAttributes(getPropertyAsString(ATTRIBS)), getPropertyAsBoolean(RETOBJ), |
777 |
getPropertyAsBoolean(DEREF)); |
788 |
getPropertyAsBoolean(DEREF)); |
778 |
res.sampleEnd(); |
789 |
res.sampleEnd(); |
779 |
while (srch.hasMore()) { |
790 |
writeSearchResults(sb, srch); |
780 |
SearchResult sr = (SearchResult) srch.next(); |
791 |
sb.append("</operation>"); |
781 |
responseData = responseData + "<dn>" + sr.getName() + "," + getPropertyAsString(SEARCHBASE) + "," |
792 |
responseData = sb.toString(); |
782 |
+ getRootdn() + "</dn>"; |
793 |
} |
783 |
responseData = responseData + "<returnedattr>" + sr.getAttributes().size() + "</returnedattr>"; |
|
|
784 |
NamingEnumeration attrlist = sr.getAttributes().getIDs(); |
785 |
while (attrlist.hasMore()) { |
786 |
String iets = (String) attrlist.next(); |
787 |
responseData = responseData + "<attribute><attributename>" + iets |
788 |
+ "</attributename>"; |
789 |
responseData = responseData |
790 |
+ "<attributevalue>" |
791 |
+ sr.getAttributes().get(iets).toString().substring( |
792 |
iets.length() + 2) + "</attributevalue></attribute>"; |
793 |
} |
794 |
} |
795 |
responseData = responseData + "</searchresult></operation>"; |
796 |
} |
797 |
|
794 |
|
798 |
} catch (NamingException ex) { |
795 |
} catch (NamingException ex) { |
799 |
String returnData = ex.toString(); |
796 |
String returnData = ex.toString(); |
Lines 818-827
Link Here
|
818 |
return res; |
815 |
return res; |
819 |
} |
816 |
} |
820 |
|
817 |
|
821 |
public void testStarted() { |
818 |
public void writeSearchResponseHeader(final StringBuffer sb) |
822 |
testStarted(""); |
819 |
{ |
823 |
} |
820 |
String scopeStr = getPropertyAsString(SCOPE); |
824 |
|
821 |
|
|
|
822 |
sb.append("<opertype>search</opertype>"); |
823 |
sb.append("<searchfilter>").append(getPropertyAsString(SEARCHFILTER)).append("</searchfilter>"); |
824 |
sb.append("<searchbase>").append(getPropertyAsString(SEARCHBASE)).append(",") |
825 |
.append(getPropertyAsString(ROOTDN)).append("</searchbase>"); |
826 |
if (scopeStr.equals("0")) |
827 |
scopeStr = OBJECT_SCOPE_STR; |
828 |
else if (scopeStr.equals("1")) |
829 |
scopeStr = ONELEVEL_SCOPE_STR; |
830 |
else if (scopeStr.equals("2")) |
831 |
scopeStr = SUBTREE_SCOPE_STR; |
832 |
sb.append("<scope>").append(scopeStr).append("</scope>"); |
833 |
sb.append("<countlimit>").append(getPropertyAsString(COUNTLIM)).append("</countlimit>"); |
834 |
sb.append("<timelimit>").append(getPropertyAsString(TIMELIM)).append("</timelimit>"); |
835 |
} |
836 |
|
837 |
/** |
838 |
* Write out search results in a stable order (including order of all subelements which might |
839 |
* be reordered like attributes and their values) so that simple textual comparison can be done, |
840 |
* unless the number of results exceeds {@link #MAX_SORTED_RESULTS} in which case just stream |
841 |
* the results out without sorting. |
842 |
*/ |
843 |
public void writeSearchResults(final StringBuffer sb, final NamingEnumeration srch) |
844 |
throws NamingException |
845 |
{ |
846 |
final ArrayList sortedResults = new ArrayList(MAX_SORTED_RESULTS); |
847 |
boolean abandonedSort; |
848 |
|
849 |
sb.append("<searchresults>"); |
850 |
// read all sortedResults into memory so we can guarantee ordering |
851 |
while (srch.hasMore() && (sortedResults.size() < MAX_SORTED_RESULTS)) { |
852 |
final SearchResult sr = (SearchResult) srch.next(); |
853 |
|
854 |
sortedResults.add(sr); |
855 |
} |
856 |
|
857 |
abandonedSort = (sortedResults.size() >= MAX_SORTED_RESULTS); |
858 |
if (!abandonedSort) |
859 |
{ |
860 |
Collections.sort(sortedResults, new Comparator() |
861 |
{ |
862 |
public int compare(Object o1, Object o2) |
863 |
{ |
864 |
String nm1 = ((SearchResult) o1).getName(); |
865 |
String nm2 = ((SearchResult) o2).getName(); |
866 |
|
867 |
if (nm1 == null) |
868 |
nm1 = ""; |
869 |
if (nm2 == null) |
870 |
nm2 = ""; |
871 |
return nm1.compareTo(nm2); |
872 |
} |
873 |
}); |
874 |
} |
875 |
|
876 |
for (Iterator it = sortedResults.iterator(); it.hasNext();) |
877 |
{ |
878 |
final SearchResult sr = (SearchResult) it.next(); |
879 |
writeSearchResult(sr, sb); |
880 |
} |
881 |
|
882 |
if (abandonedSort) |
883 |
{ |
884 |
// if abonded sort because there were too many items, then read the |
885 |
// rest of the results now... |
886 |
while (srch.hasMore()) { |
887 |
final SearchResult sr = (SearchResult) srch.next(); |
888 |
|
889 |
writeSearchResult(sr, sb); |
890 |
} |
891 |
} |
892 |
sb.append("</searchresults>"); |
893 |
} |
894 |
|
895 |
private void writeSearchResult(final SearchResult sr, final StringBuffer responseData) |
896 |
throws NamingException |
897 |
{ |
898 |
String srName = sr.getName(); |
899 |
final Attributes attrs = sr.getAttributes(); |
900 |
final ArrayList sortedAttrs; |
901 |
final String searchBase = getPropertyAsString(SEARCHBASE); |
902 |
final String rootDn = getRootdn(); |
903 |
|
904 |
responseData.append("<searchresult>"); |
905 |
responseData.append("<dn>"); |
906 |
if (!srName.endsWith(searchBase)) |
907 |
{ |
908 |
if (srName.length() > 0) |
909 |
srName = srName + ','; |
910 |
srName = srName + searchBase; |
911 |
} |
912 |
if ((rootDn.length() > 0) && !srName.endsWith(rootDn)) |
913 |
{ |
914 |
if (srName.length() > 0) |
915 |
srName = srName + ','; |
916 |
srName = srName + rootDn; |
917 |
} |
918 |
responseData.append(srName); |
919 |
responseData.append("</dn>"); |
920 |
responseData.append("<returnedattr>").append(attrs.size()).append("</returnedattr>"); |
921 |
sortedAttrs = new ArrayList(attrs.size()); |
922 |
for (NamingEnumeration en = attrs.getAll(); en.hasMore(); ) |
923 |
{ |
924 |
final Attribute attr = (Attribute) en.next(); |
925 |
|
926 |
sortedAttrs.add(attr); |
927 |
} |
928 |
Collections.sort(sortedAttrs, new Comparator() |
929 |
{ |
930 |
public int compare(Object o1, Object o2) |
931 |
{ |
932 |
String nm1 = ((Attribute) o1).getID(); |
933 |
String nm2 = ((Attribute) o2).getID(); |
934 |
|
935 |
return nm1.compareTo(nm2); |
936 |
} |
937 |
}); |
938 |
for (Iterator ait = sortedAttrs.iterator(); ait.hasNext();) |
939 |
{ |
940 |
final Attribute attr = (Attribute) ait.next(); |
941 |
|
942 |
responseData.append("<attribute><attributename>").append(attr.getID()).append("</attributename>"); |
943 |
responseData.append("<attributevalue>"); |
944 |
if (attr.size() == 1) |
945 |
responseData.append(getWriteValue(attr.get())); |
946 |
else |
947 |
{ |
948 |
final ArrayList sortedVals = new ArrayList(attr.size()); |
949 |
boolean first = true; |
950 |
|
951 |
for (NamingEnumeration ven = attr.getAll(); ven.hasMore(); ) |
952 |
{ |
953 |
final Object value = getWriteValue(ven.next()); |
954 |
|
955 |
sortedVals.add(value.toString()); |
956 |
} |
957 |
|
958 |
Collections.sort(sortedVals); |
959 |
|
960 |
for (Iterator vit = sortedVals.iterator(); vit.hasNext();) |
961 |
{ |
962 |
final String value = (String) vit.next(); |
963 |
|
964 |
if (first) |
965 |
first = false; |
966 |
else |
967 |
responseData.append(", "); |
968 |
responseData.append(value); |
969 |
} |
970 |
} |
971 |
responseData.append("</attributevalue></attribute>"); |
972 |
} |
973 |
responseData.append("</searchresult>"); |
974 |
} |
975 |
|
976 |
private String getWriteValue(final Object value) |
977 |
{ |
978 |
if (value instanceof String) |
979 |
// assume it's senstive data |
980 |
return (String)value; |
981 |
else if (value instanceof byte[]) |
982 |
try |
983 |
{ |
984 |
return new String((byte[])value, "UTF-8"); |
985 |
} |
986 |
catch (UnsupportedEncodingException e) |
987 |
{ |
988 |
log.error("this can't happen: UTF-8 character encoding not supported", e); |
989 |
} |
990 |
return value.toString(); |
991 |
} |
992 |
|
993 |
public void testStarted() { |
994 |
testStarted(""); |
995 |
} |
996 |
|
825 |
public void testEnded() { |
997 |
public void testEnded() { |
826 |
testEnded(""); |
998 |
testEnded(""); |
827 |
} |
999 |
} |