Extending the LDAP Console

Adding more commands for more fun!




Table of Contents



        Introduction

        LDAP Console Commands

        Sample AES Encryption / Decryption Command

        Sample SHA1 Hash Command

        Conclusion



Introduction



If you are a user of the LDAP Console, this article may be of interest for you! You will find here the different steps to add more commands to the console with some samples.



If you are not a user of the console, then I suggest you to have a look at it, as it's one of my favorite tools to access LDAP servers during projects...



LDAP Console Commands


The following tree will show you how commands are implemented in the tool:



Command Interface
|
\_ DefaultCommand implementing the Command Interface
|
|_ BSHEvalCommand extending the DefaultCommand class for
| calling BeanShell scripts (very powerful)
|
|_ Core*Command extending the DefaultCommand class for
| all core commands such as alias, history, etc.
|
\_ LDAP*Command extending the DefaultCommand class for
all LDAP commands such as connect, search, etc.





The Command Interface is very simple and contains the following methods:



package com.novell.ldapconsole.commands;

import com.novell.ldapconsole.LDAPInterpreter;

/*
* Created on Oct 31, 2004
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/

public interface Command
{
/**
* Get the names of the command, eg. "list", "l", "ls", "dir", etc.
* @return the names of the command
*/
public String[] getNames();

/**
* Get the help corresponding to this command
* @return the help
*/
public String getHelp();

/**
* Execute the command
* @param args parameters of the command
* @return output of the command
*/
public String executeString( LDAPInterpreter aInterpreter, String[] args );

public Object execute( LDAPInterpreter aInterpreter, String[] args );

public void setCategory( String aCategory );

public String getCategory();

public void setParams( String aParams );

public String getParams();

public void setDescription( String aDescription );

public String getDescription();

public void setNames( String[] aNames );
}





Now, to create your own command, you can extend the DefaultCommand class that offers default implementation for the above methods and simply implement your constructor and the execute command.



Here is for instance an Hello World sample (file TestHelloWorldCommand.java):



import com.novell.ldapconsole.*;
import com.novell.ldapconsole.commands.*;

public class TestHelloWorldCommand extends DefaultCommand
{
public TestHelloWorldCommand()
{
setParams("[param1] [param2] [param3] [param4] ...");
setCategory( "TEST" );
setDescription("Hello World test command");
setNames(new String[] { "hello", "helloworld", "hw" });
}

public Object execute(LDAPInterpreter aInterpreter, String[] args)
{
String oResult = "Hello World!\n";
for ( int i = 0 ; i < args.length ; i )
{
oResult = oResult args[i] "\n";
}
return oResult;
}





You can compile this little class by calling the following command (assuming you have a JDK 1.4.x installed on your system and available on the path), making sure that LDAPConsole.jar is in your classpath:



javac -classpath LDAPConsole.jar TestHelloWorldCommand.java


This will generate a TestHelloWorldCommand.class class file.



Next step isto package this class file in a new jar file. The name of the jar file must contain the full package name of the class. So in this case it will simply be TestHelloWorldCommand.jar. If the package was com.novell.ldapconsole.commands.test, the jar file would be com.novell.ldapconsole.commands.test.TestHelloWorldCommand.jar.



To create the jar file, you can use the following command:



jar cvf TestHelloWorldCommand.jar TestHelloWorldCommand.class





This will produce a jar file called TestHelloWorldCommand.jar.



Last step is to copy this jar file to the \commands directory. Once this is done, you can launch your LDAP Console and your new command will be loaded dynamically and will appear in the help!



Test it:



LDAP:/> help TEST
TEST commands:
- hello, helloworld, hw [param1] [param2] [param3] [param4] ... - Hello World test command

LDAP:/> helloworld
Hello World!
LDAP:/> hello a b c d e f
Hello World!
a
b
c
d
e
f





As you can see, you only have to customize the constructor to give the command a category, help message and command aliases. Then, all you have to do is to implement the execute method, parsing the parameters if any and write your code. I used this a lot to add new commands to encode/decode to base 64, encrypt/decrypt strings, calculate MD5/SHA1 hashes within the tool, etc.



Sample AES Encryption / Decryption Command



Here are other sample commands you can use to extend your LDAP Console. They can encrypt / decrypt a string using the symmetric AES method using a secret key.



Here is the source code of the UtilsAESEncryptCommand command class:



package com.novell.ldapconsole.commands.utils;



import com.novell.ldapconsole.*; import com.novell.ldapconsole.commands.*; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import sun.misc.BASE64Encoder;



public class UtilsAESEncryptCommand extends DefaultCommand
{

private static final byte[] initVectorData = {(byte)50, (byte)51, (byte)52, (byte)53, (byte)54, (byte)55, (byte)56, (byte)57 };

public UtilsAESEncryptCommand()
{
setParams("[string to encrypt] [secret key]");
setCategory( "UTILS" );
setDescription("Encrypt a string using AES");
setNames(new String[] { "aesencrypt", "aesenc" });
}

/**
* Encrypt a string using AES algorithm
*
* @param aText String to encrypt
* @param aKey String for the encryption key
* @return Formatted string
*/
public static String encryptAES(String aText, String aKey)
{
try
{
Cipher oCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

//setup key
byte[] oKeyBytes = new byte[16];
byte[] b = aKey.getBytes("UTF-8");
int oLen = b.length;
if (oLen > oKeyBytes.length)
oLen = oKeyBytes.length;
System.arraycopy(b, 0, oKeyBytes, 0, oLen);

SecretKeySpec oKeySpec = new SecretKeySpec(oKeyBytes, "AES");

IvParameterSpec oIvSpec = new IvParameterSpec(oKeyBytes);

oCipher.init(Cipher.ENCRYPT_MODE, oKeySpec, oIvSpec);
byte[] results = oCipher.doFinal(aText.getBytes("UTF-8"));
BASE64Encoder encoder = new BASE64Encoder();



return encoder.encode(results);
}
catch (Exception e)
{
return "-1";
}
}

public Object execute(LDAPInterpreter aInterpreter, String[] args)
{
if ( args.length > 1 )
{
String oString = args[0];
String oKey = args[1];

return encryptAES( oString, oKey );
}
else
{
return "Usage: " getHelp();
}
}
}





Here is the source code of the UtilsAESDecryptCommand command class:



package com.novell.ldapconsole.commands.utils;

import com.novell.ldapconsole.*;
import com.novell.ldapconsole.commands.*;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;

public class UtilsAESDecryptCommand extends DefaultCommand
{

private static final byte[] initVectorData = {(byte)50, (byte)51, (byte)52, (byte)53, (byte)54, (byte)55, (byte)56, (byte)57 };

public UtilsAESDecryptCommand()
{
setParams("[string to decrypt] [secret key]");
setCategory( "UTILS" );
setDescription("Decrypt a string using AES");
setNames(new String[] { "aesdecrypt", "aesdec" });
}

/**
* Decrypt a string using AES algorithm
*
* @param aText String to decrypt
* @param aKey String for the decryption key
* @return Formatted string
*/
public static String decryptAES(String aText, String aKey)
{
try
{
Cipher oCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

//setup key
byte[] oKeyBytes = new byte[16];
byte[] b = aKey.getBytes("UTF-8");
int oLen = b.length;
if (oLen > oKeyBytes.length)
oLen = oKeyBytes.length;
System.arraycopy(b, 0, oKeyBytes, 0, oLen);
SecretKeySpec oKeySpec = new SecretKeySpec(oKeyBytes, "AES");
IvParameterSpec oIvSpec = new IvParameterSpec(oKeyBytes);
oCipher.init(Cipher.DECRYPT_MODE, oKeySpec, oIvSpec);

BASE64Decoder decoder = new BASE64Decoder();
byte[] results = oCipher.doFinal(decoder.decodeBuffer(aText));

return new String(results, "UTF-8");
}
catch( Exception e )
{
return "-1";
}
}

public Object execute(LDAPInterpreter aInterpreter, String[] args)
{
if ( args.length > 1 )
{
String oString = args[0];
String oKey = args[1];

return decryptAES( oString, oKey );
}
else
{
return "Usage: " getHelp();
}
}
}





You can then compile these two classes, put them in two jar files com.novell.ldapconsole.commands.utils.UtilsAESDecryptCommand.jar and com.novell.ldapconsole.commands.utils.UtilsAESEncryptCommand.jar, and copy them in the <LDAPConsole_HOME>\commands directory.



You can test the different commands by doing the following:



LDAP:/> help UTILS
UTILS commands:
- aesdec, aesdecrypt [string to decrypt] [secret key] - Decrypt a string using AES
- aesenc, aesencrypt [string to encrypt] [secret key] - Encrypt a string using AES

LDAP:/> aesenc Hello\ World! mysecret
7qhrWJPepR2Txz8hQhJ YA==

LDAP:/> aesdec 7qhrWJPepR2Txz8hQhJ YA== mysecret
Hello World!





You can find the two jar files to copy to the commands directory in the attached zip file.



Sample SHA1 Hash Command



This sample can be useful when manipulating passwords for instance. The following command will create a SHA1 hash from a string.



The source code of the UtilsSHA1HashCommand command class:



package com.novell.ldapconsole.commands.utils;

import java.security.MessageDigest;

import com.novell.ldapconsole.*;
import com.novell.ldapconsole.commands.*;

public class UtilsSHA1HashCommand extends DefaultCommand
{
public UtilsSHA1HashCommand()
{
setParams("[string to hash]");
setCategory( "UTILS" );
setDescription("Get SHA1 hash from a string");
setNames(new String[] { "sha1hash", "sha1" });
}


public static String getHashString(String data)
{
try
{
String oResult = "";
MessageDigest md = MessageDigest.getInstance("SHA");

md.update(data.getBytes());
byte[] digest = md.digest();
for (int i = 0; i < digest.length; i )
{
String hex = Integer.toHexString(digest[i]);
if (hex.length() == 1)
hex = "0" hex;
hex = hex.substring(hex.length() - 2);
// System.out.print(hex);
oResult = oResult hex;
}

return oResult.toUpperCase();
}
catch (Exception e)
{
return "-1";
}
}

public Object execute(LDAPInterpreter aInterpreter, String[] args)
{
if ( args.length > 0 )
{
String oContent = args[0];

return getHashString( oContent );
}
else
{
return "Usage: " getHelp();
}
}
}





Testing the command:



LDAP:/> help sha1hash
Usage: sha1, sha1hash [string to hash] - Get SHA1 hash from a string

LDAP:/> sha1hash MyPassword01
776FB054DFD1F6DBFAB879D9B5FF5E56C8BB46B9





The jar file corresponding to this command can also be found in the attached zip file.



Conclusion


As you can see, it is very easy to create new commands for the LDAP Console, allowing you to do a lot more things from the tool.



If you implement new commands, don't hesitate to show me the result!



Anonymous