/**
* Copyright 2009 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.safehaus.penrose.ldap;
import java.io.StringReader;
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import org.safehaus.penrose.schema.AttributeType;
import org.safehaus.penrose.schema.ObjectClass;
import org.safehaus.penrose.schema.Schema;
import org.safehaus.penrose.schema.SchemaParser;
import org.safehaus.penrose.util.BinaryUtil;
import org.safehaus.penrose.util.TextUtil;
import org.safehaus.penrose.Penrose;
import org.ietf.ldap.*;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import com.sun.jndi.ldap.BerDecoder;
public class JNDIClient implements Cloneable {
public Logger log = LoggerFactory.getLogger(getClass());
public Collection<String> DEFAULT_BINARY_ATTRIBUTES = Arrays.asList(
"photo", "personalSignature", "audio", "jpegPhoto", "javaSerializedData",
"thumbnailPhoto", "thumbnailLogo", "userPassword", "userCertificate",
"cACertificate", "authorityRevocationList", "certificateRevocationList",
"crossCertificatePair", "x500UniqueIdentifier"
);
public Hashtable<String,Object> parameters = new Hashtable<String,Object>();
public Collection<String> binaryAttributes = new HashSet<String>();
public String url;
public String bindDn;
public Object password;
public SearchResult rootDSE;
public Schema schema;
public int defaultPageSize = 100;
public boolean connectionPool;
public LdapContext connection;
public JNDIClient(LdapContext connection, Map<String,?> parameters) throws Exception {
this.connection = connection;
init(parameters);
}
public JNDIClient(Map<String,?> parameters) throws Exception {
this(parameters, false);
}
public JNDIClient(Map<String,?> parameters, boolean connect) throws Exception {
init(parameters);
if (connect) {
try {
connection = createConnection();
} catch (Exception e) {
Penrose.errorLog.error(e.getMessage(), e);
}
}
}
public void init(Map<String,?> parameters) throws Exception {
this.parameters.putAll(parameters);
url = (String)parameters.get(Context.PROVIDER_URL);
bindDn = (String)parameters.get(Context.SECURITY_PRINCIPAL);
password = parameters.get(Context.SECURITY_CREDENTIALS);
for (String attribute : DEFAULT_BINARY_ATTRIBUTES) {
binaryAttributes.add(attribute.toLowerCase());
}
String s = (String)parameters.get("java.naming.ldap.attributes.binary");
if (s != null) {
StringTokenizer st = new StringTokenizer(s);
while (st.hasMoreTokens()) {
String attribute = st.nextToken();
binaryAttributes.add(attribute.toLowerCase());
}
}
//connectionPool = "true".equals(parameters.get("com.sun.jndi.ldap.connect.pool"));
/*
String timeout = (String)parameters.get("com.sun.jndi.ldap.connect.timeout");
if (timeout == null) {
timeout = System.getProperty("com.sun.jndi.ldap.connect.pool.timeout");
if (timeout == null) timeout = "30000"; // 30 seconds
this.parameters.put("com.sun.jndi.ldap.connect.timeout", timeout);
}
*/
}
public LdapContext reconnect(LdapContext context) throws Exception {
if (context == null) {
context = createConnection();
return context;
}
try {
context.reconnect(null);
} catch (CommunicationException e) {
context = createConnection();
}
return context;
}
public void close() throws Exception {
if (connection != null) {
log.debug("Closing LDAP connection.");
connection.close();
connection = null;
}
}
public void connect() throws Exception {
connection = createConnection();
}
public LdapContext createConnection() throws Exception {
boolean debug = log.isDebugEnabled();
if (debug) {
log.debug("Creating InitialLdapContext:");
for (String name : parameters.keySet()) {
Object value = parameters.get(name);
if (Context.SECURITY_CREDENTIALS.equals(name) && value instanceof byte[]) {
log.debug(" - " + name + ": " + new String((byte[])value));
} else {
log.debug(" - " + name + ": " + value);
}
}
}
LdapContext context = new InitialLdapContext(parameters, null);
if (debug) log.debug("Connected to "+context.getEnvironment().get(Context.PROVIDER_URL));
return context;
}
public void setConnectionPool(boolean connectionPool) {
this.connectionPool = connectionPool;
}
public boolean getConnectionPool() {
return connectionPool;
}
public LdapContext getConnection() throws Exception {
if (connectionPool) {
log.debug("Creating connection pool connection.");
return createConnection();
} else {
if (connection == null) connection = createConnection();
return connection;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Add
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void add(
AddRequest request,
AddResponse response
) throws Exception {
boolean warn = log.isWarnEnabled();
boolean debug = log.isDebugEnabled();
LdapContext context = getConnection();
try {
DN targetDn = request.getDn();
Attributes attributes = request.getAttributes();
DNBuilder db = new DNBuilder();
db.set(targetDn);
//db.append(suffix);
DN dn = db.toDn();
javax.naming.directory.Attributes attrs = convertAttributes(attributes);
if (warn) log.warn("Adding "+dn+".");
if (debug) {
log.debug("Attributes:");
NamingEnumeration ne = attrs.getAll();
while (ne.hasMore()) {
javax.naming.directory.Attribute attribute = (javax.naming.directory.Attribute)ne.next();
String name = attribute.getID();
NamingEnumeration ne2 = attribute.getAll();
while (ne2.hasMore()) {
Object value = ne2.next();
if (value instanceof byte[]) {
log.debug(" - "+name+": "+BinaryUtil.encode(BinaryUtil.BASE64, (byte[])value));
} else {
log.debug(" - "+name+": "+value);
}
}
ne2.close();
}
ne.close();
}
String escapedDn = escape(dn);
try {
context.createSubcontext(escapedDn, attrs);
} catch (CommunicationException e) {
Penrose.errorLog.error(e.getMessage(), e);
context = reconnect(context);
context.createSubcontext(escapedDn, attrs);
}
} finally {
if (connectionPool) {
context.close();
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Bind
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void bind(
BindRequest request,
BindResponse response
) throws Exception {
boolean warn = log.isWarnEnabled();
boolean debug = log.isDebugEnabled();
DN bindDn = request.getDn();
byte[] password = request.getPassword();
DNBuilder db = new DNBuilder();
db.set(bindDn);
//db.append(suffix);
DN dn = db.toDn();
this.bindDn = escape(dn);
this.password = password;
parameters.put(Context.SECURITY_PRINCIPAL, this.bindDn);
parameters.put(Context.SECURITY_CREDENTIALS, this.password);
if (warn) log.warn("Binding as "+dn+".");
if (debug) {
log.debug("Password: "+new String(password));
}
//close();
//context = connect();
LDAPUrl ldapUrl = new LDAPUrl(url);
String server = ldapUrl.getHost();
int port = ldapUrl.getPort();
LDAPConnection connection = new LDAPConnection();
connection.connect(server, port);
connection.bind(3, dn.toString(), password);
connection.disconnect();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Compare
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public boolean compare(
CompareRequest request,
CompareResponse response
) throws Exception {
boolean warn = log.isWarnEnabled();
boolean debug = log.isDebugEnabled();
LdapContext context = getConnection();
try {
DN targetDn = request.getDn();
DNBuilder db = new DNBuilder();
db.set(targetDn);
//db.append(suffix);
DN dn = db.toDn();
String filter = "("+request.getAttributeName()+"={0})";
Object args[] = new Object[] { request.getAttributeValue() };
SearchControls sc = new SearchControls();
sc.setReturningAttributes(new String[] {});
sc.setSearchScope(SearchControls.OBJECT_SCOPE);
if (warn) log.warn("Comparing "+dn+".");
if (debug) {
Object value = request.getAttributeValue();
if (value instanceof byte[]) {
log.debug(" - "+request.getAttributeName()+": "+BinaryUtil.encode(BinaryUtil.BASE64, (byte[])value));
} else {
log.debug(" - "+request.getAttributeName()+": "+value);
}
}
String escapedDn = escape(dn);
NamingEnumeration ne;
try {
ne = context.search(escapedDn, filter, args, sc);
} catch (CommunicationException e) {
Penrose.errorLog.error(e.getMessage(), e);
context = reconnect(context);
ne = context.search(escapedDn, filter, args, sc);
}
boolean b = ne.hasMore();
ne.close();
return b;
} finally {
if (connectionPool) {
context.close();
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Delete
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void delete(
DeleteRequest request,
DeleteResponse response
) throws Exception {
boolean warn = log.isWarnEnabled();
LdapContext context = getConnection();
try {
DN targetDn = request.getDn();
DNBuilder db = new DNBuilder();
db.set(targetDn);
//db.append(suffix);
DN dn = db.toDn();
if (warn) log.warn("Deleting "+dn+".");
String escapedDn = escape(dn);
try {
context.destroySubcontext(escapedDn);
} catch (CommunicationException e) {
Penrose.errorLog.error(e.getMessage(), e);
context = reconnect(context);
context.destroySubcontext(escapedDn);
}
} finally {
if (connectionPool) {
context.close();
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Modify
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void modify(
ModifyRequest request,
ModifyResponse response
) throws Exception {
boolean warn = log.isWarnEnabled();
boolean debug = log.isDebugEnabled();
LdapContext context = getConnection();
try {
DN targetDn = request.getDn();
DNBuilder db = new DNBuilder();
db.set(targetDn);
//db.append(suffix);
DN dn = db.toDn();
Collection<ModificationItem> list = new ArrayList<ModificationItem>();
for (Modification modification : request.getModifications()) {
int oldType = modification.getType();
Attribute oldAttribute = modification.getAttribute();
int newType;
switch (oldType) {
case Modification.ADD:
newType = DirContext.ADD_ATTRIBUTE;
break;
case Modification.DELETE:
newType = DirContext.REMOVE_ATTRIBUTE;
break;
case Modification.REPLACE:
newType = DirContext.REPLACE_ATTRIBUTE;
break;
default:
throw LDAP.createException(LDAP.PROTOCOL_ERROR);
}
javax.naming.directory.Attribute newAttribute = convertAttribute(oldAttribute);
list.add(new ModificationItem(newType, newAttribute));
}
ModificationItem mods[] = list.toArray(new ModificationItem[list.size()]);
if (warn) log.warn("Modifying "+dn+".");
if (debug) {
for (ModificationItem mi : mods) {
javax.naming.directory.Attribute attribute = mi.getAttribute();
int type = mi.getModificationOp();
String name = attribute.getID();
log.debug(" - "+LDAP.getModificationOperation(type)+": "+name);
NamingEnumeration ne2 = attribute.getAll();
while (ne2.hasMore()) {
Object value = ne2.next();
if (value instanceof byte[]) {
log.debug(" - "+name+": "+BinaryUtil.encode(BinaryUtil.BASE64, (byte[])value));
} else {
log.debug(" - "+name+": "+value);
}
}
ne2.close();
}
}
String escapedDn = escape(dn);
try {
context.modifyAttributes(escapedDn, mods);
} catch (CommunicationException e) {
Penrose.errorLog.error(e.getMessage(), e);
context = reconnect(context);
context.modifyAttributes(escapedDn, mods);
}
} finally {
if (connectionPool) {
context.close();
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ModRdn
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void modrdn(
ModRdnRequest request,
ModRdnResponse response
) throws Exception {
boolean warn = log.isWarnEnabled();
LdapContext context = getConnection();
try {
DN targetDn = request.getDn();
RDN newRdn = request.getNewRdn();
DNBuilder db = new DNBuilder();
db.set(targetDn);
//db.append(suffix);
DN dn = db.toDn();
if (warn) log.warn("Renaming "+dn+" to "+newRdn+".");
String escapedDn = escape(dn);
String escapedNewRdn = escape(newRdn);
try {
context.rename(escapedDn, escapedNewRdn);
} catch (CommunicationException e) {
Penrose.errorLog.error(e.getMessage(), e);
context = reconnect(context);
context.rename(escapedDn, escapedNewRdn);
}
} finally {
if (connectionPool) {
context.close();
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Search
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void search(
SearchRequest request,
SearchResponse response
) throws Exception {
boolean debug = log.isDebugEnabled();
LdapContext context = getConnection();
try {
if (debug) {
log.debug(TextUtil.displaySeparator(70));
log.debug(TextUtil.displayLine("LDAP SEARCH", 70));
log.debug(TextUtil.displaySeparator(70));
}
DNBuilder db = new DNBuilder();
db.set(request.getDn());
//db.append(suffix);
DN baseDn = db.toDn();
Collection<Object> list = new ArrayList<Object>();
String filter = request.getFilter() == null ? "(objectClass=*)" : request.getFilter().toString(list);
Object values[] = list.toArray();
int scope = request.getScope();
Collection<String> attributes = request.getAttributes();
String attributeNames[] = attributes.toArray(new String[attributes.size()]);
long sizeLimit = request.getSizeLimit();
long timeLimit = request.getTimeLimit();
boolean typesOnly = request.isTypesOnly();
//if (warn) log.warn("Searching "+baseDn+".");
if (debug) {
log.debug("Base : "+baseDn+".");
log.debug("Filter : "+filter);
for (Object value : values) {
String s;
if (value instanceof byte[]) {
s = BinaryUtil.encode(BinaryUtil.BIG_INTEGER, (byte[])value, 0, 10);
} else {
s = value.toString();
}
log.debug(" - "+s+" ("+value.getClass().getSimpleName()+")");
}
log.debug("Scope : "+ LDAP.getScope(scope));
log.debug("Attributes : "+attributes);
log.debug("Size Limit : "+sizeLimit);
log.debug("Time Limit : "+timeLimit);
}
SearchControls sc = new SearchControls();
sc.setSearchScope(scope);
sc.setReturningAttributes(attributes.isEmpty() ? null : attributeNames);
sc.setCountLimit(sizeLimit);
sc.setTimeLimit((int)timeLimit);
sc.setReturningObjFlag(!typesOnly);
Collection<Control> origControls = convertControls(request.getControls());
Collection<Control> requestControls = new ArrayList<Control>();
//String referral = "follow";
String referral = null; // "throw";
int pageSize = defaultPageSize;
for (Control control : origControls) {
String id = control.getID();
if (id.equals(ManageReferralControl.OID)) {
referral = "ignore";
} else if (id.equals(PagedResultsControl.OID)) {
byte[] value = control.getEncodedValue();
BerDecoder ber = new BerDecoder(value, 0, value.length);
ber.parseSeq(null);
pageSize = ber.parseInt();
//cookie = ber.parseOctetString(Ber.ASN_OCTET_STR, null);
} else {
requestControls.add(control);
}
}
//if (referral != null) {
// this.parameters.put(Context.REFERRAL, referral);
//}
if (pageSize > 0) {
requestControls.add(new PagedResultsControl(pageSize, Control.NONCRITICAL));
}
//Hashtable<String,Object> env = new Hashtable<String,Object>();
//env.putAll(parameters);
//env.put(Context.REFERRAL, referral);
//context = open(env);
boolean moreReferrals = true;
while (moreReferrals) {
try {
int page = 0;
byte[] cookie;
do {
if (debug) {
log.debug("Searching page #"+page);
log.debug("Request Controls:");
for (Control control : requestControls) {
log.debug(" - "+control.getID());
}
}
try {
context.setRequestControls(requestControls.toArray(new Control[requestControls.size()]));
} catch (CommunicationException e) {
Penrose.errorLog.error(e.getMessage(), e);
context = reconnect(context);
context.setRequestControls(requestControls.toArray(new Control[requestControls.size()]));
}
String escapedBaseDn = escape(baseDn);
NamingEnumeration ne;
try {
ne = context.search(escapedBaseDn, filter, values, sc);
} catch (CommunicationException e) {
Penrose.errorLog.error(e.getMessage(), e);
context = reconnect(context);
ne = context.search(escapedBaseDn, filter, values, sc);
}
while (ne.hasMore()) {
if (response.isClosed()) return;
javax.naming.directory.SearchResult sr = (javax.naming.directory.SearchResult)ne.next();
response.add(createSearchResult(request, sr));
}
ne.close();
cookie = null;
// get cookie returned by server
Control[] responseControls = context.getResponseControls();
if (responseControls != null) {
if (debug) log.debug("Response Controls:");
for (Control control : responseControls) {
if (debug) log.debug(" - "+control.getID());
if (control instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) control;
cookie = prrc.getCookie();
}
}
}
// pass cookie back to server for the next page
requestControls = new ArrayList<Control>();
for (Control control : origControls) {
String id = control.getID();
if (id.equals(ManageReferralControl.OID)) {
} else if (id.equals(PagedResultsControl.OID)) {
} else {
requestControls.add(control);
}
}
if (pageSize > 0 && cookie != null) {
requestControls.add(new PagedResultsControl(pageSize, cookie, Control.NONCRITICAL));
}
page++;
} while (cookie != null && cookie.length != 0);
moreReferrals = false;
} catch (PartialResultException e) {
Penrose.errorLog.error(e.getMessage(), e);
moreReferrals = false;
} catch (ReferralException e) {
String ref = e.getReferralInfo().toString();
if (debug) log.debug("Referral: "+ ref);
LDAPUrl url = new LDAPUrl(ref);
DN dn = new DN(url.getDN());
Attributes attrs = new Attributes();
attrs.setValue("ref", ref);
attrs.setValue("objectClass", "referral");
SearchResult result = new SearchResult(dn, attrs);
response.add(result);
//response.addReferral(ref);
moreReferrals = e.skipReferral();
if (moreReferrals) {
context = (LdapContext)e.getReferralContext();
}
}
}
} finally {
response.close();
if (connectionPool) {
context.close();
}
}
}
public SearchResult createSearchResult(
SearchRequest request,
javax.naming.directory.SearchResult sr
) throws Exception {
boolean debug = log.isDebugEnabled();
String s = sr.getName();
DNBuilder db = new DNBuilder();
if (s.startsWith("ldap://")) {
LDAPUrl url = new LDAPUrl(s);
db.set(LDAPUrl.decode(url.getDN()));
} else {
db.set(s);
}
db.append(request.getDn());
DN dn = db.toDn();
if (debug) log.debug("SearchResult: ["+dn+"]");
Attributes attributes = new Attributes();
NamingEnumeration ne = sr.getAttributes().getAll();
while (ne.hasMore()) {
javax.naming.directory.Attribute attr = (javax.naming.directory.Attribute)ne.next();
String name = attr.getID();
NamingEnumeration ne2 = attr.getAll();
while (ne2.hasMore()) {
Object value = ne2.next();
attributes.addValue(name, value);
}
ne2.close();
}
ne.close();
return new SearchResult(dn, attributes);
}
public boolean isBinaryAttribute(String name) throws Exception {
if (binaryAttributes.contains(name.toLowerCase())) return true;
getSchema();
AttributeType at = schema.getAttributeType(name);
if (at == null) return false;
String syntax = at.getSyntax();
//log.debug("Checking syntax for "+name+": "+syntax);
if ("2.5.5.7".equals(syntax) // binary
|| "2.5.5.10".equals(syntax) // octet string
//|| "2.5.5.12".equals(syntax) // unicode string
|| "2.5.5.17".equals(syntax) // sid
|| "1.3.6.1.4.1.1466.115.121.1.40".equals(syntax)
) {
return true;
}
return false;
//return binaryAttributes.contains(name.toLowerCase());
}
public SearchResult getRootDSE() throws Exception {
boolean debug = log.isDebugEnabled();
if (rootDSE != null) return rootDSE;
if (debug) log.debug("Searching Root DSE ...");
SearchRequest request = new SearchRequest();
request.setScope(SearchRequest.SCOPE_BASE);
request.setAttributes(new String[] { "*", "+" });
SearchResponse response = new SearchResponse();
search(request, response);
if (!response.hasNext()) {
rootDSE = null;
return null;
}
rootDSE = response.next();
/*
LDAPConnection connection = null;
try {
LDAPUrl ldapUrl = new LDAPUrl(url);
connection = new LDAPConnection();
connection.connect(ldapUrl.getHost(), ldapUrl.getPort());
if (bindDn != null && !"".equals(bindDn) && password != null) {
byte[] bytes;
if (password instanceof byte[]) {
bytes = (byte[])password;
} else {
bytes = password.toString().getBytes();
}
connection.bind(3, bindDn, bytes);
}
LDAPSearchResults sr = connection.search("", LDAPConnection.SCOPE_BASE, "(objectClass=*)", new String[] { "*", "+" }, false);
LDAPEntry entry = sr.next();
rootDSE = createSearchResult(entry);
} finally {
if (connection != null) try { connection.disconnect(); } catch (Exception e) { Penrose.errorLog.error(e.getMessage(), e); }
}
*/
return rootDSE;
}
public Collection<String> getNamingContexts() throws Exception {
getRootDSE();
Collection<String> list = new ArrayList<String>();
Attribute namingContexts = rootDSE.getAttributes().get("namingContexts");
if (namingContexts == null) return list;
for (Object value : namingContexts.getValues()) {
String namingContext = (String)value;
list.add(namingContext);
}
return list;
}
public Schema getSchema() throws Exception {
boolean debug = log.isDebugEnabled();
if (schema != null) return schema;
getRootDSE();
if (debug) log.debug("Searching Schema ...");
try {
Attribute schemaNamingContext = rootDSE.getAttributes().get("schemaNamingContext");
Attribute subschemaSubentry = rootDSE.getAttributes().get("subschemaSubentry");
String schemaDn;
if (schemaNamingContext != null) {
schemaDn = (String)schemaNamingContext.getValue();
if (debug) log.debug("Active Directory Schema: "+schemaDn);
schema = getActiveDirectorySchema(schemaDn);
} else if (subschemaSubentry != null) {
schemaDn = (String)subschemaSubentry.getValue();
if (debug) log.debug("Standard LDAP Schema: "+schemaDn);
schema = getLDAPSchema(schemaDn);
} else {
schemaDn = "cn=schema";
if (debug) log.debug("Default Schema: "+schemaDn);
schema = getLDAPSchema(schemaDn);
}
} catch (Exception e) {
Penrose.errorLog.error(e.getMessage(), e);
throw e;
}
return schema;
}
public Schema getActiveDirectorySchema(String schemaDn) throws Exception {
boolean debug = log.isDebugEnabled();
if (debug) log.debug("Searching "+schemaDn+" ...");
Schema schema = new Schema("ad");
getActiveDirectoryAttributeTypes(schema, schemaDn);
getActiveDirectoryObjectClasses(schema, schemaDn);
return schema;
}
public void getActiveDirectoryAttributeTypes(Schema schema, String schemaDn) throws Exception {
boolean debug = log.isDebugEnabled();
if (debug) log.debug("Search \""+ schemaDn +"\"");
LdapContext context = getConnection();
try {
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
Collection<Control> requestControls = new ArrayList<Control>();
requestControls.add(new PagedResultsControl(100, Control.NONCRITICAL));
int page = 0;
byte[] cookie;
do {
if (debug) {
log.debug("Searching page #"+page);
log.debug("Request Controls:");
for (Control control : requestControls) {
log.debug(" - "+control.getID());
}
}
NamingEnumeration ne;
try {
context.setRequestControls(requestControls.toArray(new Control[requestControls.size()]));
ne = context.search(schemaDn, "(objectClass=attributeSchema)", searchControls);
} catch (CommunicationException e) {
Penrose.errorLog.error(e.getMessage(), e);
context = reconnect(context);
context.setRequestControls(requestControls.toArray(new Control[requestControls.size()]));
ne = context.search(schemaDn, "(objectClass=attributeSchema)", searchControls);
}
while (ne.hasMore()) {
javax.naming.directory.SearchResult sr = (javax.naming.directory.SearchResult)ne.next();
javax.naming.directory.Attributes attributes = sr.getAttributes();
javax.naming.directory.Attribute lDAPDisplayName = attributes.get("lDAPDisplayName");
String atName = (String)lDAPDisplayName.get();
//log.debug(" - "+atName);
AttributeType at = new AttributeType();
at.setName(atName);
javax.naming.directory.Attribute attributeID = attributes.get("attributeID");
if (attributeID != null) at.setOid(attributeID.get().toString());
javax.naming.directory.Attribute adminDescription = attributes.get("adminDescription");
if (adminDescription != null) at.setDescription(adminDescription.get().toString());
javax.naming.directory.Attribute attributeSyntax = attributes.get("attributeSyntax");
if (attributeSyntax != null) at.setSyntax(attributeSyntax.get().toString());
javax.naming.directory.Attribute isSingleValued = attributes.get("isSingleValued");
if (isSingleValued != null) at.setSingleValued(Boolean.valueOf(isSingleValued.get().toString()));
schema.addAttributeType(at);
}
ne.close();
// get cookie returned by server
Control[] responseControls = context.getResponseControls();
cookie = null;
if (responseControls != null) {
if (debug) log.debug("Response Controls:");
for (Control control : responseControls) {
if (debug) log.debug(" - "+control.getID());
if (control instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) control;
cookie = prrc.getCookie();
}
}
}
// pass cookie back to server for the next page
requestControls = new ArrayList<Control>();
if (cookie != null) {
requestControls.add(new PagedResultsControl(100, cookie, Control.CRITICAL));
}
page++;
} while (cookie != null && cookie.length != 0);
} finally {
if (connectionPool) {
context.close();
}
}
}
public void getActiveDirectoryObjectClasses(Schema schema, String schemaDn) throws Exception {
boolean debug = log.isDebugEnabled();
LdapContext context = getConnection();
try {
if (debug) log.debug("Search \""+ schemaDn +"\"");
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
Collection<Control> requestControls = new ArrayList<Control>();
requestControls.add(new PagedResultsControl(100, Control.NONCRITICAL));
int page = 0;
byte[] cookie;
do {
if (debug) {
log.debug("Searching page #"+page);
log.debug("Request Controls:");
for (Control control : requestControls) {
log.debug(" - "+control.getID());
}
}
NamingEnumeration ne;
try {
context.setRequestControls(requestControls.toArray(new Control[requestControls.size()]));
ne = context.search(schemaDn, "(objectClass=classSchema)", searchControls);
} catch (CommunicationException e) {
Penrose.errorLog.error(e.getMessage(), e);
context = reconnect(context);
context.setRequestControls(requestControls.toArray(new Control[requestControls.size()]));
ne = context.search(schemaDn, "(objectClass=classSchema)", searchControls);
}
while (ne.hasMore()) {
javax.naming.directory.SearchResult sr = (javax.naming.directory.SearchResult)ne.next();
javax.naming.directory.Attributes attributes = sr.getAttributes();
javax.naming.directory.Attribute lDAPDisplayName = attributes.get("lDAPDisplayName");
String ocName = (String)lDAPDisplayName.get();
//log.debug(" - "+ocName);
ObjectClass oc = new ObjectClass();
oc.setName(ocName);
javax.naming.directory.Attribute governsID = attributes.get("governsID");
if (governsID != null) oc.setOid(governsID.get().toString());
javax.naming.directory.Attribute adminDescription = attributes.get("adminDescription");
if (adminDescription != null) oc.setDescription(adminDescription.get().toString());
javax.naming.directory.Attribute mustContain = attributes.get("mustContain");
if (mustContain != null) {
NamingEnumeration ne2 = mustContain.getAll();
while (ne2.hasMore()) {
String requiredAttribute = (String)ne2.next();
oc.addRequiredAttribute(requiredAttribute);
}
ne2.close();
}
javax.naming.directory.Attribute systemMustContain = attributes.get("systemMustContain");
if (systemMustContain != null) {
NamingEnumeration ne2 = systemMustContain.getAll();
while (ne2.hasMore()) {
String requiredAttribute = (String)ne2.next();
oc.addRequiredAttribute(requiredAttribute);
}
ne2.close();
}
javax.naming.directory.Attribute mayContain = attributes.get("mayContain");
if (mayContain != null) {
NamingEnumeration ne2 = mayContain.getAll();
while (ne2.hasMore()) {
String optionalAttribute = (String)ne2.next();
oc.addOptionalAttribute(optionalAttribute);
}
ne2.close();
}
javax.naming.directory.Attribute systemMayContain = attributes.get("systemMayContain");
if (systemMayContain != null) {
NamingEnumeration ne2 = systemMayContain.getAll();
while (ne2.hasMore()) {
String optionalAttribute = (String)ne2.next();
oc.addOptionalAttribute(optionalAttribute);
}
ne2.close();
}
schema.addObjectClass(oc);
}
ne.close();
// get cookie returned by server
Control[] responseControls = context.getResponseControls();
cookie = null;
if (responseControls != null) {
if (debug) log.debug("Response Controls:");
for (Control control : responseControls) {
if (debug) log.debug(" - "+control.getID());
if (control instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) control;
cookie = prrc.getCookie();
}
}
}
// pass cookie back to server for the next page
requestControls = new ArrayList<Control>();
if (cookie != null) {
requestControls.add(new PagedResultsControl(100, cookie, Control.CRITICAL));
}
page++;
} while (cookie != null && cookie.length != 0);
} finally {
if (connectionPool) {
context.close();
}
}
}
public Schema getLDAPSchema(String schemaDn) throws Exception {
boolean debug = log.isDebugEnabled();
LdapContext context = getConnection();
try {
Schema schema = new Schema("ldap");
if (debug) log.debug("Searching "+schemaDn+" ...");
SearchControls ctls = new SearchControls();
ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
ctls.setReturningAttributes(new String[] { "attributeTypes", "objectClasses" });
NamingEnumeration ne;
try {
ne = context.search(schemaDn, "(objectClass=*)", ctls);
} catch (CommunicationException e) {
Penrose.errorLog.error(e.getMessage(), e);
context = reconnect(context);
ne = context.search(schemaDn, "(objectClass=*)", ctls);
}
javax.naming.directory.SearchResult sr = (javax.naming.directory.SearchResult)ne.next();
javax.naming.directory.Attributes attributes = sr.getAttributes();
//log.debug("Object Classes:");
javax.naming.directory.Attribute objectClasses = attributes.get("objectClasses");
NamingEnumeration ne2 = objectClasses.getAll();
while (ne2.hasMore()) {
String value = (String)ne2.next();
ObjectClass oc = parseObjectClass(value);
if (oc == null) continue;
//log.debug(" - "+oc.getName());
schema.addObjectClass(oc);
}
ne2.close();
//log.debug("Attribute Types:");
javax.naming.directory.Attribute attributeTypes = attributes.get("attributeTypes");
NamingEnumeration ne3 = attributeTypes.getAll();
while (ne3.hasMore()) {
String value = (String)ne3.next();
AttributeType at = parseAttributeType(value);
if (at == null) continue;
//log.debug(" - "+at.getName());
schema.addAttributeType(at);
}
ne3.close();
ne.close();
return schema;
} finally {
if (connectionPool) {
context.close();
}
}
}
public AttributeType parseAttributeType(String line) throws Exception {
try {
line = "attributetype "+line;
SchemaParser parser = new SchemaParser(new StringReader(line));
Schema schema = parser.parse();
return schema.getAttributeTypes().iterator().next();
} catch (Exception e) {
Penrose.errorLog.error(e.getMessage(), e);
return null;
}
}
public ObjectClass parseObjectClass(String line) throws Exception {
try {
line = "objectclass "+line;
SchemaParser parser = new SchemaParser(new StringReader(line));
Schema schema = parser.parse();
return schema.getObjectClasses().iterator().next();
} catch (Exception e) {
Penrose.errorLog.error(e.getMessage(), e);
return null;
}
}
public Collection<Control> convertControls(Collection<org.safehaus.penrose.control.Control> controls) throws Exception {
Collection<Control> list = new ArrayList<Control>();
for (org.safehaus.penrose.control.Control control : controls) {
String oid = control.getOid();
boolean critical = control.isCritical();
byte[] value = control.getValue();
list.add(new BasicControl(oid, critical, value));
}
return list;
}
public SearchResult find(String dn) throws Exception {
SearchRequest request = new SearchRequest();
request.setDn(dn);
request.setScope(SearchRequest.SCOPE_BASE);
SearchResponse response = new SearchResponse();
search(request, response);
if (!response.hasNext()) return null;
return response.next();
}
public Collection<SearchResult> getChildren(String baseDn) throws Exception {
boolean debug = log.isDebugEnabled();
Collection<SearchResult> results = new ArrayList<SearchResult>();
DNBuilder db = new DNBuilder();
db.set(baseDn);
DN searchBase = db.toDn();
if (searchBase.isEmpty()) {
SearchResult rootDse = getRootDSE();
Attributes attributes = rootDse.getAttributes();
Attribute attribute = attributes.get("namingContexts");
for (Object value : attribute.getValues()) {
String dn = (String)value;
if (debug) log.debug(" - "+dn);
SearchResult entry = find(dn);
results.add(entry);
}
} else {
if (debug) log.debug("Searching "+searchBase+":");
SearchRequest request = new SearchRequest();
request.setDn(baseDn);
request.setScope(SearchRequest.SCOPE_ONE);
SearchResponse response = new SearchResponse();
search(request, response);
while (response.hasNext()) {
SearchResult sr = response.next();
if (debug) log.debug(" - "+sr.getDn());
results.add(sr);
}
}
return results;
}
public static String[] parseURL(String s) {
String[] result = new String[4]; // 0 = ldap/ldaps, 1 = hostname, 2 = port, 3 = suffix
int i = s.indexOf("://");
if (i < 0) return null;
result[0] = s.substring(0, i);
int j = s.indexOf("/", i+3);
String hostPort;
if (j > 0) {
hostPort = s.substring(i+3, j);
result[3] = s.substring(j+1);
} else {
hostPort = s.substring(i+3);
}
int k = hostPort.indexOf(":");
if (k < 0) {
result[1] = hostPort;
if ("ldap".equals(result[0])) {
result[2] = "389";
} else if ("ldaps".equals(result[0])) {
result[2] = "636";
} else {
return null;
}
} else {
result[1] = hostPort.substring(0, k);
result[2] = hostPort.substring(k+1);
}
return result;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public void setRootDSE(SearchResult rootDSE) {
this.rootDSE = rootDSE;
}
public void setSchema(Schema schema) {
this.schema = schema;
}
public javax.naming.directory.Attributes convertAttributes(Attributes attributes) throws Exception {
javax.naming.directory.Attributes attrs = new BasicAttributes();
for (Attribute attribute : attributes.getAll()) {
attrs.put(convertAttribute(attribute));
}
return attrs;
}
public javax.naming.directory.Attribute convertAttribute(Attribute attribute) throws Exception {
String name = attribute.getName();
javax.naming.directory.Attribute attr = new BasicAttribute(name);
for (Object value : attribute.getValues()) {
attr.add(value);
}
return attr;
}
public String escape(RDN rdn) {
return escape(rdn.toString());
}
public String escape(DN dn) {
return escape(dn.toString());
}
public String escape(String string) {
boolean debug = log.isDebugEnabled();
String s = string.replaceAll("/", "\\\\/");
if (debug) log.debug("Escape ["+string+"] => ["+s+"].");
return s;
}
public Object clone() throws CloneNotSupportedException {
JNDIClient client = (JNDIClient)super.clone();
client.parameters = new Hashtable<String,Object>();
client.parameters.putAll(parameters);
client.binaryAttributes = new ArrayList<String>();
client.binaryAttributes.addAll(binaryAttributes);
client.url = url;
client.rootDSE = rootDSE;
client.schema = schema;
client.defaultPageSize = defaultPageSize;
client.connectionPool = connectionPool;
try {
if (connection != null) client.connection = connection.newInstance(null);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
return client;
}
}