зеркало из https://github.com/mozilla/gecko-dev.git
284 строки
9.4 KiB
Java
284 строки
9.4 KiB
Java
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (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.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1999 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
package com.netscape.jndi.ldap;
|
|
|
|
import javax.naming.*;
|
|
import javax.naming.directory.*;
|
|
import javax.naming.ldap.*;
|
|
|
|
import netscape.ldap.*;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* Common utility methods
|
|
*
|
|
*/
|
|
class ProviderUtils {
|
|
|
|
public static final String DEFAULT_FILTER = "(objectclass=*)";
|
|
|
|
static int jndiSearchScopeToLdap(int jndiScope) throws NamingException {
|
|
int scope = -1;
|
|
if (jndiScope == SearchControls.SUBTREE_SCOPE) {
|
|
scope = LDAPConnection.SCOPE_SUB;
|
|
}
|
|
else if (jndiScope == SearchControls.ONELEVEL_SCOPE) {
|
|
scope = LDAPConnection.SCOPE_ONE;
|
|
}
|
|
else if (jndiScope == SearchControls.OBJECT_SCOPE) {
|
|
scope = LDAPConnection.SCOPE_BASE;
|
|
}
|
|
else {
|
|
throw new InvalidSearchControlsException("Illegal value for the search scope");
|
|
}
|
|
return scope;
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert Attribute List to a LDAP filter
|
|
*
|
|
* @return LDAP Filter
|
|
* @throw NamingException
|
|
* @param attrs An Attribute List
|
|
*/
|
|
static String attributesToFilter(Attributes attrs) throws NamingException{
|
|
|
|
if (attrs == null || attrs.size() == 0) {
|
|
return DEFAULT_FILTER;
|
|
}
|
|
|
|
String filter = "";
|
|
|
|
for (NamingEnumeration attrEnum = attrs.getAll(); attrEnum.hasMore();) {
|
|
Attribute attrib = (Attribute) attrEnum.next();
|
|
|
|
//Has attributes any values
|
|
if ( attrib.size() == 0) {
|
|
// test only for presence of the attribute
|
|
filter += "(" + attrib.getID() + "=*)";
|
|
continue;
|
|
}
|
|
|
|
// Add attribute values to the filter, ecsaping if necessary
|
|
String attrValues = "";
|
|
for (NamingEnumeration valEnum = attrib.getAll(); valEnum.hasMore();) {
|
|
Object val = valEnum.next();
|
|
if (val instanceof String) {
|
|
attrValues += "(" + attrib.getID() + "=" + escapeString((String)val) +")";
|
|
}
|
|
else if (val instanceof byte[]) {
|
|
attrValues += "(" + attrib.getID() + "=" + escapeBytes((byte[])val) +")";
|
|
}
|
|
else if (val == null) {
|
|
//null is allowed value in Attribute.add(Object), accept it just in case
|
|
attrValues += "(" + attrib.getID() + "=*)";
|
|
}
|
|
else {
|
|
throw new NamingException(
|
|
"Wrong Attribute value, expecting String or byte[]");
|
|
}
|
|
}
|
|
filter += (attrib.size() > 1) ? ("(|" + attrValues + ")") : attrValues;
|
|
}
|
|
|
|
return (attrs.size() > 1) ? ("(&" + filter + ")") : filter;
|
|
}
|
|
|
|
|
|
/**
|
|
* Expand filterExpr. Each occurrence of a variable "{n}", where n is a non-negative
|
|
* integer, is replaced with a variable from the filterArgs array indexed by the 'n'.
|
|
* FilterArgs can be Strings or byte[] and they are escaped according to the RFC2254
|
|
*/
|
|
static String expandFilterExpr(String filterExpr, Object[] filterArgs) throws InvalidSearchFilterException{
|
|
StringTokenizer tok = new StringTokenizer(filterExpr, "{}", /*returnTokens=*/true);
|
|
|
|
if (tok.countTokens() == 1) {
|
|
return filterExpr; // No escape characters
|
|
}
|
|
|
|
StringBuffer out= new StringBuffer();
|
|
boolean expectVarIdx = false, expectVarOff = false;
|
|
Object arg= null;
|
|
while (tok.hasMoreTokens()) {
|
|
String s = tok.nextToken();
|
|
|
|
if (expectVarIdx) {
|
|
expectVarIdx = false;
|
|
try {
|
|
int idx = Integer.parseInt(s);
|
|
arg = filterArgs[idx];
|
|
expectVarOff = true;
|
|
}
|
|
catch (IndexOutOfBoundsException e) {
|
|
throw new InvalidSearchFilterException("Filter expression variable index out of bounds");
|
|
}
|
|
|
|
catch (Exception e) {
|
|
throw new InvalidSearchFilterException("Invalid filter expression");
|
|
}
|
|
}
|
|
|
|
else if (expectVarOff) {
|
|
expectVarOff = false;
|
|
if (!s.equals("}")) {
|
|
throw new InvalidSearchFilterException("Invalid filter expression");
|
|
}
|
|
if (arg instanceof String) {
|
|
out.append(escapeString((String)arg));
|
|
}
|
|
else if (arg instanceof byte[]) {
|
|
out.append(escapeBytes((byte[])arg));
|
|
}
|
|
else {
|
|
throw new InvalidSearchFilterException("Invalid filter argument type");
|
|
}
|
|
arg = null;
|
|
}
|
|
|
|
else if (s.equals("{")) {
|
|
expectVarIdx = true;
|
|
}
|
|
else {
|
|
out.append(s);
|
|
}
|
|
}
|
|
if (expectVarIdx || expectVarOff) {
|
|
throw new InvalidSearchFilterException("Invalid filter expression");
|
|
}
|
|
return out.toString();
|
|
}
|
|
|
|
|
|
/**
|
|
* Escape a string according to the RFC 2254
|
|
*/
|
|
static String escapeString(String str) {
|
|
String charToEscape = "\\*()\000";
|
|
StringTokenizer tok = new StringTokenizer(str, charToEscape, /*returnTokens=*/true);
|
|
|
|
if (tok.countTokens() == 1) {
|
|
return str; // No escape characters
|
|
}
|
|
|
|
StringBuffer out= new StringBuffer();
|
|
while (tok.hasMoreTokens()) {
|
|
String s = tok.nextToken();
|
|
|
|
if (s.equals("*")) {
|
|
out.append("\\2a");
|
|
}
|
|
else if (s.equals("(")) {
|
|
out.append("\\28");
|
|
}
|
|
else if (s.equals(")")) {
|
|
out.append("\\29");
|
|
}
|
|
else if (s.equals("\\")) {
|
|
out.append("\\5c");
|
|
}
|
|
else if (s.equals("\000")) {
|
|
out.append("\\00");
|
|
}
|
|
else {
|
|
out.append(s);
|
|
}
|
|
}
|
|
return out.toString();
|
|
}
|
|
|
|
|
|
/**
|
|
* Escape a byte array according to the RFC 2254
|
|
*/
|
|
static final String hexDigits="0123456789abcdef";
|
|
|
|
static String escapeBytes(byte[] bytes) {
|
|
StringBuffer out = new StringBuffer("");
|
|
for (int i=0; i < bytes.length; i++) {
|
|
|
|
int low = bytes[i] & 0x0f;
|
|
int high = (bytes[i] & 0xf0) >> 4;
|
|
out.append("\\");
|
|
out.append(hexDigits.charAt(high));
|
|
out.append(hexDigits.charAt(low));
|
|
}
|
|
return out.toString();
|
|
}
|
|
|
|
/**
|
|
* A method used only for testing
|
|
*/
|
|
private static void testAttributesToFilter() {
|
|
try {
|
|
System.out.println(attributesToFilter(null));
|
|
|
|
BasicAttributes attrs = new BasicAttributes(true);
|
|
|
|
System.out.println(attrs + " = " + attributesToFilter(attrs));
|
|
|
|
attrs.put (new BasicAttribute("attr1", "val1"));
|
|
attrs.put (new BasicAttribute("attr2", "(val2)\\*x"));
|
|
attrs.put (new BasicAttribute("attr3"));
|
|
BasicAttribute attr4 = new BasicAttribute("attr4", "val41");
|
|
attr4.add("val42");
|
|
attrs.put(attr4);
|
|
attrs.put("attr5", new byte[] { (byte)0x23, (byte)0x3, (byte)0x0, (byte)0xab, (byte)0xff});
|
|
System.out.println(attrs + " = " +attributesToFilter(attrs));
|
|
}
|
|
catch (Exception e) {
|
|
System.err.println(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A method used only for testing
|
|
*/
|
|
private static void testFilterExpr() {
|
|
try {
|
|
String filterExpr = "(&(attr0={0})(attr1={1}))";
|
|
Object [] args = new Object[] { "val*0", new byte[] { (byte)0xf0, (byte) 0x3a}};
|
|
String filter = null;
|
|
filter = expandFilterExpr(filterExpr, args);
|
|
System.out.println(filterExpr + " -> " + filter);
|
|
}
|
|
catch (Exception e) {
|
|
System.err.println(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test
|
|
*/
|
|
public static void main(String[] args) {
|
|
/*testAttributesToFilter();
|
|
String x = "012\0003";
|
|
byte[] b = x.getBytes();
|
|
for (int i=0; i < b.length; i++) {
|
|
System.out.println(i+"="+b[i]);
|
|
}*/
|
|
testFilterExpr();
|
|
}
|
|
}
|