package jeffaschenk.commons.frameworks.cnxidx.utility.ldap;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.TreeMap;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchResult;
/**
* Java class for providing either simple display print form of a
* NamingEnumerated Search result or true RFC complient LDIF form of
* output for IRR Directory Entries.
*
* @author jeff.schenk
* @version 2.0 $Revision
* Developed 2001-2002
*/
public class idxIRROutput {
private static String MP = "idxIRROutput: ";
private static String ObjectClassName = "objectclass";
private static String UserPasswordName = "userpassword";
private static String cnxidaXObjectBlob = "cnxidaxobjectblob";
/**
* Print Directory Entry Attribute and value pairs from a
* search result.
* We will report on all objectclasses and naming attributes
* first. The userPassword Attribute will always be displayed
* as hidden in a "********" form. Long attribute values, such
* as the cnxidoxobjectblob will display a shortened display.
*
* @param sl JNDI search results.
* @param dnbase Current DN base to properly reflect full DN.
* @return int count of entries processed.
*/
public static int PrintSearchList(NamingEnumeration sl, String dnbase) {
int EntryCount = 0;
if (sl == null) {
return (EntryCount);
} else {
try {
while (sl.hasMore()) {
SearchResult si = (SearchResult) sl.next();
EntryCount++;
// *****************************
// Formulate the DN.
//
String DN = null;
if (dnbase.equals("")) {
DN = si.getName();
} else if (!si.isRelative()) {
DN = si.getName();
} else if (si.getName().equals("")) {
DN = dnbase;
} else {
DN = si.getName() + "," + dnbase;
}
// ************************************
// Is the DN from a deReference Alias?
// If so, then we have a URL, we need
// to remove the URL.
//
if (!si.isRelative()) {
DN = extractDNfromURL(DN);
}
// ******************************************
// Write out the DN.
// Do not write out a JNDI Quoted DN.
// That is not LDIF Compliant.
//
idxParseDN pDN = new idxParseDN(DN);
if (pDN.isQuoted()) {
System.out.println("dn: " + pDN.getDN());
} else {
System.out.println("dn: " + DN);
}
// Obtain Attributes
Attributes entryattrs = si.getAttributes();
// First Write out Objectclasses.
Attribute eo = entryattrs.get(ObjectClassName);
if (eo != null) {
for (NamingEnumeration eov = eo.getAll(); eov.hasMore(); ) {
System.out.println(eo.getID() + ": " + eov.next());
}
} // End of check for null if.
// Obtain Naming Attribute Next.
if (!"".equals(pDN.getNamingAttribute())) {
Attribute en = entryattrs.get(pDN.getNamingAttribute());
if (en != null) {
for (NamingEnumeration env = en.getAll(); env.hasMore(); ) {
System.out.println(en.getID() + ": " + env.next());
}
} // End of check for null if.
} // End of Naming Attribute.
// Finish Obtaining remaining Attributes,
// in no special sequence.
for (NamingEnumeration ea = entryattrs.getAll(); ea.hasMore(); ) {
Attribute attr = (Attribute) ea.next();
if ((!ObjectClassName.equalsIgnoreCase(attr.getID())) &&
(!pDN.getNamingAttribute().equalsIgnoreCase(attr.getID()))) {
for (NamingEnumeration ev = attr.getAll(); ev.hasMore(); ) {
String Aname = attr.getID();
Aname = Aname.toLowerCase();
Object Aobject = ev.next();
if (Aname.startsWith(UserPasswordName)) {
// *****************************
// Show A trimmed Down Version.
System.out.println(UserPasswordName + ": " +
"********");
} else if (cnxidaXObjectBlob.equalsIgnoreCase(attr.getID())) {
// *****************************
// Show A trimmed Down Version.
String blob;
blob = (String) Aobject;
blob = blob.replace('\n', ' ');
int obloblen = blob.length();
if (blob.length() > 64) {
blob = blob.substring(0, 25) + " ...... " +
blob.substring((blob.length() - 25));
} // end of if.
System.out.println(attr.getID() +
": " + blob + ", Full Length:[" + obloblen + "]");
} else if (Aobject instanceof byte[]) {
System.out.println(attr.getID() +
": [ Binary data " + ((byte[]) Aobject).length + " in length ]");
} else { // Show normal Attributes as is...
System.out.println(attr.getID() +
": " + Aobject);
} // End of Else.
} // End of Inner For Loop.
} // End of If.
} // End of Outer For Loop
System.out.println("");
} // End of While Loop
} catch (NamingException e) {
System.err.println(MP + "Cannot continue listing search results - " + e);
return (-1);
} catch (Exception e) {
System.err.println(MP + "Cannot continue listing search results - " + e);
e.printStackTrace();
return (-1);
} // End of Exception
} // End of Else
return (EntryCount);
} // End of PrintSearchList
/**
* Print Directory Entry Attribute and value pairs from a
* search result.
* We will report on all objectclasses and naming attributes
* first. The userPassword Attribute will always be displayed
* as hidden in a "********" form.
* If the NICE is TRUE then the Long attribute values, such
* as the cnxidoxobjectblob will display in full.
*
* @param sl JNDI search results.
* @param dnbase Current DN base to properly reflect full DN.
* @param _NICE NICE Output Indicator.
* @return int count of entries processed.
*/
public static int PrintSearchList(NamingEnumeration sl, String dnbase, boolean _NICE) {
// ***************************************************
// If not nice output, return the abridged version.
if (!_NICE) {
return (PrintSearchList(sl, dnbase));
}
int EntryCount = 0;
if (sl == null) {
return (EntryCount);
} else {
try {
while (sl.hasMore()) {
SearchResult si = (SearchResult) sl.next();
EntryCount++;
// *************************************
// Formulate the DN.
//
String DN = null;
if (dnbase.equals("")) {
DN = si.getName();
} else if (!si.isRelative()) {
DN = si.getName();
} else if (si.getName().equals("")) {
DN = dnbase;
} else {
DN = si.getName() + "," + dnbase;
}
// ************************************
// Is the DN from a deReference Alias?
// If so, then we have a URL, we need
// to remove the URL.
//
if (!si.isRelative()) {
DN = extractDNfromURL(DN);
}
// ******************************************
// Write out the DN.
// Do not write out a JNDI Quoted DN.
// That is not LDIF Compliant.
//
idxParseDN pDN = new idxParseDN(DN);
if (pDN.isQuoted()) {
System.out.println("dn: " + pDN.getDN());
} else {
System.out.println("dn: " + DN);
}
// Obtain Attributes
Attributes entryattrs = si.getAttributes();
// First Write out Objectclasses.
Attribute eo = entryattrs.get(ObjectClassName);
if (eo != null) {
for (NamingEnumeration eov = eo.getAll(); eov.hasMore(); ) {
System.out.println(eo.getID() + ": " + eov.next());
}
} // End of check for null if.
// Obtain Naming Attribute Next.
if (!"".equals(pDN.getNamingAttribute())) {
Attribute en = entryattrs.get(pDN.getNamingAttribute());
if (en != null) {
for (NamingEnumeration env = en.getAll(); env.hasMore(); ) {
System.out.println(en.getID() + ": " + env.next());
}
} // End of check for null if.
} // End of Naming Attribute.
// Finish Obtaining remaining Attributes,
// in no special sequence.
for (NamingEnumeration ea = entryattrs.getAll(); ea.hasMore(); ) {
Attribute attr = (Attribute) ea.next();
if ((!ObjectClassName.equalsIgnoreCase(attr.getID())) &&
(!pDN.getNamingAttribute().equalsIgnoreCase(attr.getID()))) {
for (NamingEnumeration ev = attr.getAll(); ev.hasMore(); ) {
String Aname = attr.getID();
Aname = Aname.toLowerCase();
Object Aobject = ev.next();
if (Aname.startsWith(UserPasswordName)) {
// *****************************
// Show A trimmed Down Version.
System.out.println(UserPasswordName + ": " +
"********");
} else if (cnxidaXObjectBlob.equalsIgnoreCase(attr.getID())) {
String blob;
blob = (String) Aobject;
System.out.println(attr.getID() +
": Data Length:[" + blob.length() + "]");
System.out.println(attr.getID() +
": " + blob);
} else if (Aobject instanceof byte[]) {
System.out.println(attr.getID() +
": [ Binary data " + ((byte[]) Aobject).length + " in length ]");
} else { // Show normal Attributes as is...
System.out.println(attr.getID() +
": " + Aobject);
} // End of Else.
} // End of Inner For Loop.
} // End of If.
} // End of Outer For Loop
System.out.println("");
} // End of While Loop
} catch (NamingException e) {
System.err.println(MP + "Cannot continue listing search results - " + e);
return (-1);
} catch (Exception e) {
System.err.println(MP + "Cannot continue listing search results - " + e);
e.printStackTrace();
return (-1);
} // End of Exception
} // End of Else
return (EntryCount);
} // End of PrintSearchList
/**
* Output Directory Entries in RFC complient LDIF
* Attribute and value pairs from a search result.
* We will report on all objectclasses and naming attributes
* first. Normal Base64 attribute encoding will apply as well.
*
* @param sl JNDI search results.
* @param dnbase Current DN base to properly reflect full DN.
* @param LDIFOUT output stream where LDIF written.
* @param _NICE NICE DN Output indicator.
* @return int count of entries processed.
* @throws Exception when unrecoverable error occurs.
*/
public static int LDIFSearchList(NamingEnumeration sl,
String dnbase,
BufferedWriter LDIFOUT,
boolean _NICE)
throws Exception, IOException {
int EntryCount = 0;
if (sl == null) {
return (EntryCount);
} else {
try {
while (sl.hasMore()) {
SearchResult si = (SearchResult) sl.next();
EntryCount++;
// ******************************************
// Formulate the DN.
//
String DN = null;
if (dnbase.equals("")) {
DN = si.getName();
} else if (!si.isRelative()) {
DN = si.getName();
} else if (si.getName().equals("")) {
DN = dnbase;
} else {
DN = si.getName() + "," + dnbase;
}
// ************************************
// Is the DN from a deReference Alias?
// If so, then we have a URL, we need
// to remove the URL.
//
if (!si.isRelative()) {
DN = extractDNfromURL(DN);
}
// ******************************************
// Write out the DN.
// Do not write out a JNDI Quoted DN.
// That is not LDIF Compliant.
//
idxParseDN pDN = new idxParseDN(DN);
if (_NICE) {
LDIFOUT.write("dn: ");
if (pDN.isQuoted()) {
LDIFOUT.write(pDN.getDN());
} else {
LDIFOUT.write(DN);
}
LDIFOUT.write("\n");
} else {
if (pDN.isQuoted()) {
WriteLDIF("dn", pDN.getDN(), LDIFOUT);
} else {
WriteLDIF("dn", DN, LDIFOUT);
}
} // End of DN Output.
// Obtain the entries Attributes.
Attributes entryattrs = si.getAttributes();
// Obtain ObjectClass First.
Attribute eo = entryattrs.get(ObjectClassName);
if (eo != null) {
for (NamingEnumeration eov = eo.getAll(); eov.hasMore(); ) {
WriteLDIF(eo.getID(), eov.next(), LDIFOUT);
}
} // End of check for null if.
// Obtain Naming Attribute Next.
if (!"".equals(pDN.getNamingAttribute())) {
Attribute en = entryattrs.get(pDN.getNamingAttribute());
if (en != null) {
for (NamingEnumeration env = en.getAll(); env.hasMore(); ) {
WriteLDIF(en.getID(), env.next(), LDIFOUT);
}
} // End of check for null if.
} // End of Naming Attribute.
// Finish Obtaining remaining Attributes,
// in no special sequence.
for (NamingEnumeration ea = entryattrs.getAll(); ea.hasMore(); ) {
Attribute attr = (Attribute) ea.next();
if ((!ObjectClassName.equalsIgnoreCase(attr.getID())) &&
(!pDN.getNamingAttribute().equalsIgnoreCase(attr.getID()))) {
for (NamingEnumeration ev = attr.getAll(); ev.hasMore(); ) {
WriteLDIF(attr.getID(), ev.next(), LDIFOUT);
}
} // End of If
} // End of Outer For Loop
WriteLDIF("", "", LDIFOUT);
} // End of While Loop
} catch (NamingException e) {
System.err.println(MP + "Naming Exception, Cannot continue obtaining search results, " + e);
throw e;
} catch (Exception e) {
System.err.println(MP + "Exception, Cannot continue obtaining search results, " + e);
e.printStackTrace();
throw e;
} // End of Exception
} // End of Else
return (EntryCount);
} // End of LDIFSearchList
/**
* Output Attributes and incoming DN in RFC complient LDIF
* Attribute and value pairs.
* We will report on all objectclasses and naming attributes
* first. Normal Base64 attribute encoding will apply as well.
*
* @param SourceDN Full DN.
* @param entryattrs JNDI Attributes Object.
* @param LDIFOUT output stream where LDIF written.
* @param _NICE NICE DN output indicator.
* @throws Exception when unrecoverable error occurs.
*/
public static void EntryToLDIF(String SourceDN,
Attributes entryattrs,
BufferedWriter LDIFOUT,
boolean _NICE)
throws Exception, IOException {
if (entryattrs == null) {
return;
}
try {
// ******************************************
// Write out the DN.
// Do not write out a JNDI Quoted DN.
// That is not LDIF Compliant.
//
idxParseDN pDN = new idxParseDN(SourceDN);
if (_NICE) {
LDIFOUT.write("dn: ");
if (pDN.isQuoted()) {
LDIFOUT.write(pDN.getDN());
} else {
LDIFOUT.write(SourceDN);
}
LDIFOUT.write("\n");
} else {
if (pDN.isQuoted()) {
WriteLDIF("dn", pDN.getDN(), LDIFOUT);
} else {
WriteLDIF("dn", SourceDN, LDIFOUT);
}
} // End of DN Output.
// Obtain ObjectClass First.
Attribute eo = entryattrs.get(ObjectClassName);
if (eo != null) {
for (NamingEnumeration eov = eo.getAll(); eov.hasMore(); ) {
WriteLDIF(eo.getID(), eov.next(), LDIFOUT);
}
} // End of check for null if.
// Obtain Naming Attribute Next.
if (!"".equals(pDN.getNamingAttribute())) {
Attribute en = entryattrs.get(pDN.getNamingAttribute());
if (en != null) {
for (NamingEnumeration env = en.getAll(); env.hasMore(); ) {
WriteLDIF(en.getID(), env.next(), LDIFOUT);
}
} // End of check for null if.
} // End of Naming Attribute.
// Finish Obtaining remaining Attributes,
// in no special sequence.
for (NamingEnumeration ea = entryattrs.getAll(); ea.hasMore(); ) {
Attribute attr = (Attribute) ea.next();
if ((!ObjectClassName.equalsIgnoreCase(attr.getID())) &&
(!pDN.getNamingAttribute().equalsIgnoreCase(attr.getID()))) {
for (NamingEnumeration ev = attr.getAll(); ev.hasMore(); ) {
WriteLDIF(attr.getID(), ev.next(), LDIFOUT);
}
} // End of If
} // End of Outer For Loop
WriteLDIF("", "", LDIFOUT);
} catch (Exception e) {
System.err.println(MP + "EntryToLDIF() Exception, Unable to Formulate LDIF Output, " + e);
e.printStackTrace();
throw e;
} // End of Exception
} // End of EntryToLDIF
/**
* Output Attributes and incoming DN in RFC complient LDIF
* Attribute and value pairs, while preserving the case
* of the Attribute Name or ID.
* We will report on all objectclasses and naming attributes
* first. Normal Base64 attribute encoding will apply as well.
*
* @param SourceDN Full DN.
* @param entryattrs JNDI Attributes Object.
* @param LDIFOUT output stream where LDIF written.
* @param _NICE NICE DN output indicator.
* @throws Exception when unrecoverable error occurs.
*/
public static void EntryToLDIFPreservingAttributeNameCase(String SourceDN,
Attributes entryattrs,
BufferedWriter LDIFOUT,
boolean _NICE)
throws Exception, IOException {
if (entryattrs == null) {
return;
}
TreeMap<String,String> AttrNameMap = new TreeMap<>();
String aname = null;
try {
// ******************************************
// Write out the DN.
// Do not write out a JNDI Quoted DN.
// That is not LDIF Compliant.
//
idxParseDN pDN = new idxParseDN(SourceDN);
if (_NICE) {
LDIFOUT.write("dn: ");
if (pDN.isQuoted()) {
LDIFOUT.write(pDN.getDN());
} else {
LDIFOUT.write(SourceDN);
}
LDIFOUT.write("\n");
} else {
if (pDN.isQuoted()) {
WriteLDIF("dn", pDN.getDN(), LDIFOUT);
} else {
WriteLDIF("dn", SourceDN, LDIFOUT);
}
} // End of DN Output.
// Since this method preserves case of the Attribute
// Name, we must formulate the lookup table for
// Attribute Name Normalization.
//
for (NamingEnumeration avl = entryattrs.getIDs(); avl.hasMore(); ) {
aname = (String) avl.next();
AttrNameMap.put(aname.toLowerCase(), aname);
} // End of For Loop.
// Obtain ObjectClass First.
aname = (String) AttrNameMap.get(ObjectClassName.toLowerCase());
Attribute eo = entryattrs.get(aname);
if (eo != null) {
for (NamingEnumeration eov = eo.getAll(); eov.hasMore(); ) {
WriteLDIF(eo.getID(), eov.next(), LDIFOUT);
}
} // End of check for null if.
// Obtain Naming Attribute Next.
if (!"".equals(pDN.getNamingAttribute())) {
aname = (String) AttrNameMap.get(pDN.getNamingAttribute().toLowerCase());
Attribute en = entryattrs.get(aname);
if (en != null) {
for (NamingEnumeration env = en.getAll(); env.hasMore(); ) {
WriteLDIF(en.getID(), env.next(), LDIFOUT);
}
} // End of check for null if.
} // End of Naming Attribute.
// Finish Obtaining remaining Attributes,
// in no special sequence.
for (NamingEnumeration ea = entryattrs.getAll(); ea.hasMore(); ) {
Attribute attr = (Attribute) ea.next();
if ((!ObjectClassName.equalsIgnoreCase(attr.getID())) &&
(!pDN.getNamingAttribute().equalsIgnoreCase(attr.getID()))) {
for (NamingEnumeration ev = attr.getAll(); ev.hasMore(); ) {
WriteLDIF(attr.getID(), ev.next(), LDIFOUT);
}
} // End of If
} // End of Outer For Loop
WriteLDIF("", "", LDIFOUT);
} catch (Exception e) {
System.err.println(MP + "EntryToLDIF() Exception, Unable to Formulate LDIF Output, " + e);
e.printStackTrace();
throw e;
} // End of Exception
} // End of EntryToLDIFPreservingAttributeNameCase
/**
* Outputs RFC complient LDIF data.
* Normal Base64 attribute encoding will apply as well.
*
* @param AttributeName Atrribute Name.
* @param obvalue Attribute Object Value.
* @param LDIFOUT output stream where LDIF written.
*/
public static void WriteLDIF(String AttributeName,
Object obvalue,
BufferedWriter LDIFOUT)
throws IOException {
String strvalue;
String Tag;
char[] jd;
int LDIFLineSize = 76;
char[] LDIFLineSeperator = {'\n'};
// **************************************************
// Tag and get data value into character byte form.
if (obvalue instanceof byte[]) {
Tag = AttributeName + ":: ";
jd = idxIRRBase64.encode((byte[]) obvalue);
} else {
strvalue = obvalue.toString();
if (ShouldEncode(strvalue)) {
Tag = AttributeName + ":: ";
jd = idxIRRBase64.encode(strvalue.getBytes());
} else if ((strvalue.equals("")) &&
(AttributeName.equals(""))) {
LDIFOUT.write(LDIFLineSeperator);
return;
} else if (strvalue.equals("")) {
Tag = AttributeName + ":";
LDIFOUT.write(Tag);
LDIFOUT.write(LDIFLineSeperator);
return;
} else {
Tag = AttributeName + ": ";
jd = strvalue.toCharArray();
}
} // End of Else.
// *************************************
// Now Write the Data and first line.
int linelen = LDIFLineSize + 1 - Tag.length();
LDIFOUT.write(Tag);
if (jd.length + Tag.length() <= LDIFLineSize) {
LDIFOUT.write(jd);
LDIFOUT.write(LDIFLineSeperator);
return;
}
// **************************************************
// Write out all subsequent LDIF continuation lines.
LDIFOUT.write(jd, 0, linelen);
LDIFOUT.write(LDIFLineSeperator);
for (int jl = linelen; jl < jd.length; jl += LDIFLineSize) {
LDIFOUT.write(" ");
if (jl + LDIFLineSize > jd.length) {
LDIFOUT.write(jd, jl, jd.length - jl);
} else {
LDIFOUT.write(jd, jl, LDIFLineSize);
}
LDIFOUT.write(LDIFLineSeperator);
} // End of For Loop.
} // End of WriteLDIF
/**
* Class to determine if the string data should be Base64 encoded or not.
* This follows the standard LDIF rules for encoding as presented in the
* RFC.
*
* @param str Attribute Value String.
* @return boolean indicator whether value should be Base64 encoded
* or not.
*/
public static boolean ShouldEncode(String str) {
char SAFE_CHAR_EXCEPTIONS[] = {'\n', '\r', '\t', 0};
char SAFE_INIT_CHAR_EXCEPTIONS[] = {'\n', '\r', '\t', 32, ':', '<', 0};
// Are there safe initial character exceptions in the content?
for (int ji = 0; ji < SAFE_INIT_CHAR_EXCEPTIONS.length; ji++) {
if (str.indexOf(SAFE_INIT_CHAR_EXCEPTIONS[ji]) == 0) {
return (true);
}
}
// Are there safe character exceptions in the content?
for (int ji = 0; ji < SAFE_CHAR_EXCEPTIONS.length; ji++) {
if (str.indexOf(SAFE_CHAR_EXCEPTIONS[ji]) != -1) {
return (true);
}
}
// Is there a trailing space?
if (str.endsWith(" ")) {
return (true);
}
return (false);
} // End of ShouldEncode.
/**
* Class to output the current Directory Schema to STDOUT.
*
* @param ctx current established Directory Context.
*/
public static void PrintSchema(DirContext ctx) {
try {
// Get the schema tree root
DirContext schema = ctx.getSchema("");
// List contents of root
NamingEnumeration bds = schema.list("");
while (bds.hasMore()) {
String schemaobjectname = ((NameClassPair) (bds.next())).getName();
System.out.println("Schema Object Name: [" + schemaobjectname + "]");
// Get the schema tree root
DirContext ocs = (DirContext) schema.lookup(schemaobjectname);
// List contents of root
NamingEnumeration bdsi = ocs.list("");
while (bdsi.hasMore()) {
String ocname = ((NameClassPair) (bdsi.next())).getName();
System.out.println(schemaobjectname + ": [" + ocname + "]");
// Get object's attributes
Attributes ocAttrs = ocs.getAttributes(ocname);
System.out.println(ocAttrs);
} // End of Inner While.
ocs.close();
} // End of Outer While.
schema.close();
} catch (NamingException e) {
System.err.println(MP + "Error Obtaining Schema: " + e);
e.printStackTrace();
} // End of Exception
} // End of PrintSchema Class
/**
* Class to extract the DN from a URL CompoundName.
*
* @param _DN Incoming URL with DN, from an Alias.
* @return String Extracted DN.
*/
public static String extractDNfromURL(String _DN) {
// ***************************
// Make sure we have a string.
if ((_DN == null) ||
(_DN.equals(""))) {
return (_DN);
}
// ***************************
// Create an LDAPURL Object
// from the incoming String.
//
LDAPUrl _ldapurl = null;
try {
_ldapurl = new LDAPUrl(_DN);
} catch (java.net.MalformedURLException mue) {
// *******************************
// This is a malformed URL, return
// Null.
return ("");
} // End of Exception.
// ***************************
// Extract the DN.
//
return (_ldapurl.getDN());
} // End of extractDNfromURL Class
} ///:~ End of idxIRROutput Class