Showing posts with label ECMAScript. Show all posts
Showing posts with label ECMAScript. Show all posts

Tuesday, August 31, 2010

ECMAScript to run a command on windows

I had the need to try to run a batch script on the command line using Novell IDM.  I was able to develop a quick function in ECMAScript in order to accomplish this task.  Simply call the following function from policy and pass it the full string of what you want run on the command line and it'll return any output it may return.  Very simple, yet infinitely useful.

importPackage(Packages.java.io);
importPackage(Packages.java.util);

function runCommand(commandString)
{
        var runtime = new java.lang.Runtime.getRuntime();
        var process = runtime.exec(commandString);
        var is = process.getInputStream();
        var isr = new Packages.java.io.InputStreamReader(is);
        var br = new Packages.java.io.BufferedReader(isr);
        var line = new java.lang.String();
        var fulltext = new java.lang.String();
       
        while ((line = br.readLine()) != null )
        {
            fulltext = fulltext + line;
        }
       
        return fulltext;
}

Wednesday, May 19, 2010

Novell IDM CSV Fanout Driver

In a traditional Novell IDM CSV driver, you have one event, which will create one output CSV file.  You can use the output transform to format the CSV files output so it does not necessarily have to be a true CSV file, but a text file of any format you wish.

I was recently presented with a unique challenge where I needed upwards of 120 or so CSV files for a single event.  The total number of files was dependent on a few factors, but they are irrelevant as that logic was programmed in policy.  The part that was pretty nifty was creating my own version of a CSV fanout driver.

Instead of using the traditional CSV driver, I used a Null Services driver.  I used typical policy to determine my outputs, but did so in a loop, so I could loop through each iteration of an output.  Each time I hit a valid output, I constructed my text file format and held it in a local variable.  It looked something like this:


<do-set-local-variable name="lv.outputString" scope="policy">
      <arg-string>
            Construct string here
      </arg-string>
</do-set-local-variable>


I then added a ECMAScript object to my driver and added it to the driver configuration.  The ECMAScript was very simple:

importPackage(Packages.java.io);

function writeFile(fileName, contentString)
{
    try {
        var printFile = new Packages.java.io.PrintStream(fileName);
        printFile.print(contentString);
        printFile.close();
        return "";
   } catch (e) {
        return e.toString();
   }
}

All I needed to do at this point was use an XPATH expression to call my ECMAScript function.  I pass it the path to the file I want to create and the string I created.  The function will create the file with the contents I specified.

The only thing to note about this is you will need to use unique filenames.  The way I found to most easily do this is to use a timestamp.  The following file path uses a timestamp down to the millisecond, so it should always be unique.

   <do-set-local-variable name="lv.outputFile" scope="policy">
      <arg-string>
          <token-global-variable name="outputfilelocation"/>
          <token-text xml:space="preserve">\</token-text>
          <token-time format="yyyyMMddHHmmssSSS"/>
          <token-text xml:space="preserve">.csv</token-text>
      </arg-string>
   </do-set-local-variable>

Once we have the output file string, the contents string, and the ECMAScript object created and added to the driver, we just need to use our XPATH expression to call it and write out our files.

  <do-set-local-variable name="result" scope="policy">
     <arg-string>
          <token-xpath expression="es:writeFile($lv.outputFile,$lv.outputString)"/>
     </arg-string>
  </do-set-local-variable>

The local variable "result" is holding the return value, which should be blank.  If it is not blank, then there was a problem and the exception that was caught should be held in this value.  This can be used for simple error checking.

Tuesday, April 27, 2010

3DES Encrypt data with Novell IDM

If you check the blog prior to this one, I developed a method to call a web service URL from within any driver for Novell IDM.  This is all good, but what happens if we need to pass sensitive data in this URL.  We can't just do a GET operation with a URL that has a password in clear text, that's just asking for trouble.

What we do to protect this data is to throw some 3DES encryption on it before we throw the args on the end.  With the 3DES encryption, we also need a function to URLEncode the contents so the URL is written in a language the browser can send across.  Once again, I used some ECMAScript and code to get this done.

Please note, you will need to generate your own encryption key, then also use this key and similar code on the remote side to decrypt the contents to read it.

Here is the code.  The first portion is two functions.  The first function encrypts the data string passed to it, then passes it to the second function which will URLEncode it.

importPackage(Packages.javax.crypto);
importPackage(Packages.javax.crypto.spec);
importPackage(Packages.java.security.spec);
importPackage(Packages.java.io);
importPackage(Packages.sun.misc);
importClass(java.net.URLEncoder);

function DESEncrypt(theString) {
    try {
            var secretKey   = new SecretKeySpec(new Packages.sun.misc.BASE64Decoder().decodeBuffer(new java.lang.String("thisiswhereyouputyourkey")), "DESede");
            var ecipher = new Cipher.getInstance("DESede");
            ecipher.init(Cipher.ENCRYPT_MODE, secretKey);
            var utf8 = new java.lang.String(theString).getBytes("UTF8");
            var enc = ecipher.doFinal(utf8);
            return EncodeURLString(new Packages.sun.misc.BASE64Encoder().encode(enc));
        } catch (e) {
            return e.toString();
        }
       
        return null;
}

function EncodeURLString(theContents) {
    try {
        return new URLEncoder.encode(theContents, "UTF8");
    } catch (e) {
        return e.toString();
    }
    return null;
}

Once this ECMAScript is saved, pushed up, then called into your IDM, you can call it like this:

            <do-set-local-variable name="lv.EncryptedArgs" scope="policy">
                <arg-string>
                    <token-xpath expression="es:DESEncrypt($myArgs)"/>
                </arg-string>
            </do-set-local-variable>

Now, you have your encrypted arguments stored in a local variable, all nice and URL encoded.  Just tack it on the end of a URL and call it with the code defined in the previous blog article and you have now sent encrypted data across the wire.

Web Services with Novell IDM

So I have a pretty unique request.  A customer asked me to integrate IDM with a system that doesn't have a standard interface that I could use to integrate.  It did, however, have an API that we could use to create our own interface.  The customers programmer decided that the easiest way to implement this would be to setup a web service for me to call. 

While initially, I thought this was a candidate for the SOAP driver, I realized that this driver is overkill for the simplicity of this implementation.  This is a sample of how we would be creating a user in the system from IDM:

http://www.server.com/addUser?username=testuser&fname=test&lname=user&password=Passw0rd&othreattribute=other1&....

SOAP is complete overkill, I just need to construct a simlpe URL and call a linux wget on that URL.  The resulting status message would be returned instead of a typical HTML page when the API code processed the request.

I did some research and decided the easiest way to implement this would be to use ECMAScript to call some custom code that would very easily call my URL and return the result for me.  I would shove the result into a local variable in policy then jam that sucker into an attribute on the user object in eDirectory.  Seems like a very simple implementation, here is how I was able to do it.

Below is the ECMAScript for the function that I wrote.  Its a simple function, urlGet. You pass it the URL and it returns whatever is returned when a GET operation is performed on that URL.

importClass(java.net.URL);
importClass(java.io.InputStreamReader);
importClass(java.lang.StringBuilder);

function urlGet(urlString) {
try {
var url = new java.net.URL(String(urlString));
var stream = url.openStream();
var reader = new java.io.InputStreamReader(stream, "UTF-8");
var sb = new java.lang.StringBuilder();
var c;
while ((c = reader.read()) != -1) {
sb.append(String.fromCharCode(c));
}
return sb.toString();
} catch(e) {
return e.toString();
}
}

Now, we post that ECMAScript and use it in our driver with the following.  It will use the URL that is stored in the Local Variable myURL and return the results back to lv.URLResult.

            <do-set-local-variable name="lv.URLResult" scope="policy">
                <arg-string>
                    <token-xpath expression="es:urlGet($myURL)"/>
                </arg-string>
            </do-set-local-variable>

Program some logic to store the result in some sort of status attribute, then business logic to construct the correct URL and your can very easily IDM enable a web service based system.