提交 456a5009 编写于 作者: X xuelei

6916202: More cases of invalid ldap filters accepted and processed

Reviewed-by: vinnie, weijun
上级 0c5f24ec
/*
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -33,6 +33,7 @@ import java.io.IOException;
/**
* LDAP (RFC-1960) and LDAPv3 (RFC-2254) search filters.
*
* @author Xuelei Fan
* @author Vincent Ryan
* @author Jagane Sundar
* @author Rosanna Lee
......@@ -258,7 +259,7 @@ final class Filter {
byte[] answer = new byte[j];
System.arraycopy(tbuf, 0, answer, 0, j);
if (dbg) {
Ber.dumpBER(System.err, null, answer, 0, j);
Ber.dumpBER(System.err, "", answer, 0, j);
}
return answer;
}
......@@ -330,7 +331,7 @@ final class Filter {
}
valueStart = eq + 1; // value starts after equal sign
valueStart = eq + 1; // value starts after equal sign
valueEnd = filtEnd;
typeStart = filtStart; // beginning of string
......@@ -355,20 +356,199 @@ final class Filter {
break;
default:
typeEnd = eq;
//initializing ftype to make the compiler happy
ftype = 0x00;
break;
}
if (dbg) {
System.err.println("type: " + typeStart + ", " + typeEnd);
System.err.println("value: " + valueStart + ", " + valueEnd);
}
// check validity of type
//
// RFC4512 defines the type as the following ABNF:
// attr = attributedescription
// attributedescription = attributetype options
// attributetype = oid
// oid = descr / numericoid
// descr = keystring
// keystring = leadkeychar *keychar
// leadkeychar = ALPHA
// keychar = ALPHA / DIGIT / HYPHEN
// numericoid = number 1*( DOT number )
// number = DIGIT / ( LDIGIT 1*DIGIT )
// options = *( SEMI option )
// option = 1*keychar
//
// And RFC4515 defines the extensible type as the following ABNF:
// attr [dnattrs] [matchingrule] / [dnattrs] matchingrule
int optionsStart = -1;
int extensibleStart = -1;
if ((filter[typeStart] >= '0' && filter[typeStart] <= '9') ||
(filter[typeStart] >= 'A' && filter[typeStart] <= 'Z') ||
(filter[typeStart] >= 'a' && filter[typeStart] <= 'z')) {
boolean isNumericOid =
filter[typeStart] >= '0' && filter[typeStart] <= '9';
for (int i = typeStart + 1; i < typeEnd; i++) {
// ';' is an indicator of attribute options
if (filter[i] == ';') {
if (isNumericOid && filter[i - 1] == '.') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
// attribute options
optionsStart = i;
break;
}
// ':' is an indicator of extensible rules
if (filter[i] == ':' && ftype == LDAP_FILTER_EXT) {
if (isNumericOid && filter[i - 1] == '.') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
// extensible matching
extensibleStart = i;
break;
}
if (isNumericOid) {
// numeric object identifier
if ((filter[i] == '.' && filter[i - 1] == '.') ||
(filter[i] != '.' &&
!(filter[i] >= '0' && filter[i] <= '9'))) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
} else {
// descriptor
if (filter[i] != '-' &&
!(filter[i] >= '0' && filter[i] <= '9') &&
!(filter[i] >= 'A' && filter[i] <= 'Z') &&
!(filter[i] >= 'a' && filter[i] <= 'z')) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
}
}
} else if (ftype == LDAP_FILTER_EXT && filter[typeStart] == ':') {
// extensible matching
extensibleStart = typeStart;
} else {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
// check attribute options
if (optionsStart > 0) {
for (int i = optionsStart + 1; i < typeEnd; i++) {
if (filter[i] == ';') {
if (filter[i - 1] == ';') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
continue;
}
// ':' is an indicator of extensible rules
if (filter[i] == ':' && ftype == LDAP_FILTER_EXT) {
if (filter[i - 1] == ';') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
// extensible matching
extensibleStart = i;
break;
}
if (filter[i] != '-' &&
!(filter[i] >= '0' && filter[i] <= '9') &&
!(filter[i] >= 'A' && filter[i] <= 'Z') &&
!(filter[i] >= 'a' && filter[i] <= 'z')) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
}
}
// check extensible matching
if (extensibleStart > 0) {
boolean isMatchingRule = false;
for (int i = extensibleStart + 1; i < typeEnd; i++) {
if (filter[i] == ':') {
throw new InvalidSearchFilterException(
"invalid attribute description");
} else if ((filter[i] >= '0' && filter[i] <= '9') ||
(filter[i] >= 'A' && filter[i] <= 'Z') ||
(filter[i] >= 'a' && filter[i] <= 'z')) {
boolean isNumericOid = filter[i] >= '0' && filter[i] <= '9';
i++;
for (int j = i; j < typeEnd; j++, i++) {
// allows no more than two extensible rules
if (filter[j] == ':') {
if (isMatchingRule) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
if (isNumericOid && filter[j - 1] == '.') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
isMatchingRule = true;
break;
}
if (isNumericOid) {
// numeric object identifier
if ((filter[j] == '.' && filter[j - 1] == '.') ||
(filter[j] != '.' &&
!(filter[j] >= '0' && filter[j] <= '9'))) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
} else {
// descriptor
if (filter[j] != '-' &&
!(filter[j] >= '0' && filter[j] <= '9') &&
!(filter[j] >= 'A' && filter[j] <= 'Z') &&
!(filter[j] >= 'a' && filter[j] <= 'z')) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
}
}
} else {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
}
}
// ensure the latest byte is not isolated
if (filter[typeEnd - 1] == '.' || filter[typeEnd - 1] == ';' ||
filter[typeEnd - 1] == ':') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
if (typeEnd == eq) { // filter type is of "equal"
if (findUnescaped(filter, '*', valueStart, valueEnd) == -1) {
ftype = LDAP_FILTER_EQUALITY;
} else if (filter[valueStart] == '*' && valueStart == (valueEnd - 1)) {
} else if (filter[valueStart] == '*' &&
valueStart == (valueEnd - 1)) {
ftype = LDAP_FILTER_PRESENT;
} else {
encodeSubstringFilter(ber, filter,
typeStart, typeEnd, valueStart, valueEnd);
return;
}
break;
}
if (dbg) {
System.err.println("type: " + typeStart + ", " + typeEnd);
System.err.println("value: " + valueStart + ", " + valueEnd);
}
if (ftype == LDAP_FILTER_PRESENT) {
......@@ -379,7 +559,7 @@ final class Filter {
} else {
ber.beginSeq(ftype);
ber.encodeOctetString(filter, Ber.ASN_OCTET_STR,
typeStart, typeEnd-typeStart);
typeStart, typeEnd - typeStart);
ber.encodeOctetString(
unescapeFilterValue(filter, valueStart, valueEnd),
Ber.ASN_OCTET_STR);
......@@ -623,7 +803,8 @@ final class Filter {
//
////////////////////////////////////////////////////////////////////////////
private static final boolean dbg = false;
// private static final boolean dbg = false;
private static final boolean dbg = true;
private static int dbgIndent = 0;
private static void dprint(String msg) {
......
/*
* Copyright 2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/**
* @test
* @bug 6916202
* @summary More cases of invalid ldap filters accepted and processed
* @run main/othervm InvalidLdapFilters valid (cn=Babs)
* @run main/othervm InvalidLdapFilters valid (&(cn=Bob))
* @run main/othervm InvalidLdapFilters valid (&(objectClass=*)(uid=*))
* @run main/othervm InvalidLdapFilters valid (|(cn=Bob))
* @run main/othervm InvalidLdapFilters valid (|(objectClass=*)(uid=*))
* @run main/othervm InvalidLdapFilters valid (!(cn=Tim))
* @run main/othervm InvalidLdapFilters valid (!(!(cn=Tim)))
* @run main/othervm InvalidLdapFilters valid (!(&(objectClass=*)(uid=*)))
* @run main/othervm InvalidLdapFilters valid (!(|(objectClass=*)(uid=*)))
* @run main/othervm InvalidLdapFilters valid (o=univ*of*mich*)
* @run main/othervm InvalidLdapFilters valid (seeAlso=)
* @run main/othervm InvalidLdapFilters valid (cn:caseExactMatch:=Flintstone)
* @run main/othervm InvalidLdapFilters valid (cn:=Betty)
* @run main/othervm InvalidLdapFilters valid (sn:dn:2.4.6.8.10:=Barney)
* @run main/othervm InvalidLdapFilters valid (o:dn:=Ace)
* @run main/othervm InvalidLdapFilters valid (:1.2.3:=Wilma)
* @run main/othervm InvalidLdapFilters valid (:DN:2.4.6.8.10:=Dino)
* @run main/othervm InvalidLdapFilters valid (1.2.3=abc)
* @run main/othervm InvalidLdapFilters valid (cn;lang-de;lang-en=abc)
* @run main/othervm InvalidLdapFilters valid (owner=abc)
* @run main/othervm InvalidLdapFilters valid (sn;lang-en:dn:2.4.6.8.10:=Barney)
* @run main/othervm InvalidLdapFilters valid
(&(objectClass=Person)(|(sn=Jensen)(cn=Bab*)))
* @run main/othervm InvalidLdapFilters invalid "(&(cn=Robert Dean)))"
* @run main/othervm InvalidLdapFilters invalid (&|(cn=Bob))
* @run main/othervm InvalidLdapFilters invalid (&&(cn=Bob))
* @run main/othervm InvalidLdapFilters invalid (|&(cn=Bob))
* @run main/othervm InvalidLdapFilters invalid (||(cn=Bob))
* @run main/othervm InvalidLdapFilters invalid (:1.2.:=Wilma)
* @run main/othervm InvalidLdapFilters invalid (::DN:2.4.6.8.10:=Dino)
* @run main/othervm InvalidLdapFilters invalid (:DN::2.4.6.8.10:=Dino)
* @run main/othervm InvalidLdapFilters invalid (:DN:2.4.6.8.10::=Dino)
* @run main/othervm InvalidLdapFilters invalid (:DN:2.4.6..8.10:=Dino)
* @run main/othervm InvalidLdapFilters invalid (:DN:2.4.6.8.:=Dino)
* @run main/othervm InvalidLdapFilters invalid (1.2.;::=abc)
* @run main/othervm InvalidLdapFilters invalid (1.2.3;::=abc)
* @run main/othervm InvalidLdapFilters invalid (1.2.3;x;=abc)
* @run main/othervm InvalidLdapFilters invalid (1.2.3:x::=abc)
* @run main/othervm InvalidLdapFilters invalid (1.2.3:x=abc)
* @run main/othervm InvalidLdapFilters invalid (sn;:dn:2.4.6.8.10:=Barney)
* @run main/othervm InvalidLdapFilters invalid "\"((objectClass=*)&(uid=*))\""
* @run main/othervm InvalidLdapFilters invalid "&(objectClass=*)(uid=*)"
* @run main/othervm InvalidLdapFilters invalid "(:DN:2.4.6.8.10:cn:=Dino)"
* @run main/othervm InvalidLdapFilters invalid "(:DN:2.4.6.8.10:cn=Dino)"
* @run main/othervm InvalidLdapFilters invalid
"((objectCategory=person)(cn=u)(!(cn=u2*)))"
* @run main/othervm InvalidLdapFilters invalid
"((&(objectClass=user)(cn=andy*)(cn=steve*)(cn=bob*)))"
*
* @author Xuelei Fan
*/
import java.io.*;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.Properties;
import java.util.Hashtable;
import java.net.Socket;
import java.net.ServerSocket;
public class InvalidLdapFilters {
// Should we run the client or server in a separate thread?
//
// Both sides can throw exceptions, but do you have a preference
// as to which side should be the main thread.
static boolean separateServerThread = true;
// use any free port by default
volatile int serverPort = 0;
// Is the server ready to serve?
volatile static boolean serverReady = false;
// Define the server side of the test.
//
// If the server prematurely exits, serverReady will be set to true
// to avoid infinite hangs.
void doServerSide() throws Exception {
ServerSocket serverSock = new ServerSocket(serverPort);
// signal client, it's ready to accecpt connection
serverPort = serverSock.getLocalPort();
serverReady = true;
// accept a connection
Socket socket = serverSock.accept();
System.out.println("Server: Connection accepted");
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
// read the bindRequest
while (is.read() != -1) {
// ignore
is.skip(is.available());
break;
}
byte[] bindResponse = {0x30, 0x0C, 0x02, 0x01, 0x01, 0x61, 0x07, 0x0A,
0x01, 0x00, 0x04, 0x00, 0x04, 0x00};
// write bindResponse
os.write(bindResponse);
os.flush();
// ignore any more request.
while (is.read() != -1) {
// ignore
is.skip(is.available());
}
is.close();
os.close();
socket.close();
serverSock.close();
}
// Define the client side of the test.
//
// If the server prematurely exits, serverReady will be set to true
// to avoid infinite hangs.
void doClientSide() throws Exception {
// Wait for server to get started.
while (!serverReady) {
Thread.sleep(50);
}
// set up the environment for creating the initial context
Hashtable<Object, Object> env = new Hashtable<Object, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:" + serverPort);
env.put("com.sun.jndi.ldap.read.timeout", "1000");
// env.put(Context.SECURITY_AUTHENTICATION, "simple");
// env.put(Context.SECURITY_PRINCIPAL,"cn=root");
// env.put(Context.SECURITY_CREDENTIALS,"root");
// create initial context
DirContext context = new InitialDirContext(env);
// searching
SearchControls scs = new SearchControls();
scs.setSearchScope(SearchControls.SUBTREE_SCOPE);
try {
NamingEnumeration answer =
context.search("o=sun,c=us", searchFilter, scs);
} catch (InvalidSearchFilterException isfe) {
if (filterIsValid) {
// unexpected filter exception.
throw new Exception("Unexpected ISFE", isfe);
} else {
// ignore, it is the expected filter exception.
System.out.println("Expected exception: " + isfe.getMessage());
}
} catch (NamingException ne) {
// maybe a read timeout exception, as the server does not response.
if (filterIsValid) {
System.out.println("Expected exception: " + ne.getMessage());
} else {
throw new Exception("Not an InvalidSearchFilterException", ne);
}
}
context.close();
}
private static boolean filterIsValid;
private static String searchFilter;
private static void parseArguments(String[] args) {
System.out.println("arguments length: " + args.length);
if (args[0].equals("valid")) {
filterIsValid = true;
}
searchFilter = args[1];
}
/*
* ============================================================
* The remainder is just support stuff
*/
// client and server thread
Thread clientThread = null;
Thread serverThread = null;
// client and server exceptions
volatile Exception serverException = null;
volatile Exception clientException = null;
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
System.err.println(e);
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
// Primary constructor, used to drive remainder of the test.
InvalidLdapFilters() throws Exception {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null) {
System.out.print("Server Exception:");
throw serverException;
}
if (clientException != null) {
System.out.print("Client Exception:");
throw clientException;
}
}
public static void main(String[] args) throws Exception {
// parse the customized arguments
parseArguments(args);
// start the test
new InvalidLdapFilters();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册