Introduction

Novell Identity Manager provides direct integration of Novell Audit events in policy, which can be received by Novell Identity Audit (http://www.novell.com/products/audit/) or Novell Sentinel (http://www.novell.com/products/sentinel/). This is great, if your site is using NIA or Sentinel. But if you are using some other centralized auditing and logging system, it is not likely that it understands NIA or Sentinel events. In this case, you are more likely to be asked to send it something it does understand. Fortunately, many of these systems understand standard Unix syslog messages.

While IDM does not provide a way to send syslog messages, it does provide for extensibility by writing your own extentions in Java. This allows you to do things that the designers of IDM did not envision needing, or didn’t think enough people would want to be worth implementing in DirXML Script.

Also fortunately, the Apache Project (http://www.apache.org) has an interesting set of logging functions available in Java. This is their Log4J project (http://logging.apache.org/log4j/index.html). It allows a Java application to have a standard logging interface, where it can send messages. The Log4J code then routes those messages to various destinations. These destinations can be as simple as printing the message on screen, or logging it to a file, or sending it to a syslog receiver. Better yet, the message format is completely customizable, as are the message destinations, all at runtime via a simple configuration file. Log4J impliments several message levels (Debug, Info, Warn, Error, Fatal) indicating the severity of the message, and message routing can be done on these as well. It would take a few minutes to configure it, via the file, but you could easily route Debug log messages to a syslog server on your workstation, while Info messages are routed to your central security syslog server, while Warn and Error messages are routed to a file, and Error messages are sent via email to your mobile phone so you know immediately when there is a problem.

Step One: The Java Wrapper

In order to make all of this happen, a bit of work has to be done. Rather than just submit the finished Jar file and some documentation, I’m using this as an opportunity to show how easy it is to add new functionality to IDM.

Log4J has a couple of interesting classes. The first impliments a way to configure Log4J at runtime instead of having to have configuration code in your policies. The second impliments the logging interface. That’s it, all you need to worry about. In order to access these, though, we need to wrap them in a Java class that IDM can call. To do that, we need a Jar file, compiled from some simple Java source.


code: IDM2Log4J.java


//
// IDMLog4J
// A wrapper class for Apache Project's Log4J to be used by Novell Identity Manager
//
// Copyright 2009 - May be freely used and distributed so long as these comments remain intact
// David Gersic
// Northern Illinois University
// dgersic@niu.edu
//

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class IDM2Log4J {

    public static void main(String[] args)
    {
        IDM2Log4J idmLog = new IDM2Log4J();

        log( "IDMLog", "IDMlog4j.properties", "debug", "Test" );
        log( "IDMLog", "IDMlog4j.properties", "info", "Test" );
        log( "IDMLog", "IDMlog4j.properties", "warn", "Test" );
        log( "IDMLog", "IDMlog4j.properties", "error", "Test" );
        log( "IDMLog", "IDMlog4j.properties", "fatal", "Test" );
    }

    public static void log(String logName, String logPropFile, String logType, String logText)
    {
        Logger logger = Logger.getLogger( logName );
        PropertyConfigurator.configure( logPropFile );
        if( logType.equalsIgnoreCase( "debug" ) )
            logger.debug( logText );
        if( logType.equalsIgnoreCase( "info" ) )
            logger.info( logText );
        if( logType.equalsIgnoreCase( "warn" ) )
            logger.warn( logText );
        if( logType.equalsIgnoreCase( "error" ) )
            logger.error( logText );
        if( logType.equalsIgnoreCase( "fatal" ) )
            logger.fatal( logText );
    }
}


Save this code as IDM2Log4J.java. It’s pretty simple code, but a quick explanation of what is included is that the class (IDM2Log4J) has one public member (log), which takes a four input parameters, and uses the Logger.getLogger() to instantiate a logger, then uses PropertyConfigurator.configure() to configure that logger, and logger.debug(), logger.info(), logger.warn(), logger.error(), and logger.fatal() to send messages to it.

The input parameters specify the log name, the logger property (configuration) file, the log type (debug, info, warn, error, fatal), and the log message.

The main() function provides for a way to test this outside of IDM. We’ll see that later after we have built the Jar file. In order to do that, you need a few more files.


code: .project


<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
        <name>IDM2Log4j</name>
        <comment></comment>
        <projects>
        </projects>
        <buildSpec/>
        <natures/>
</projectDescription>


Save this as .project in the same directory as the IDM2Log4J.java file.


code: .classpath


<?xml version="1.0" encoding="UTF-8"?>
<classpath>
        <classpathentry kind="src" path=""/>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
        <classpathentry kind="lib" path="log4j-1.2.15.jar"/>
        <classpathentry kind="output" path=""/>
</classpath>


Save this as .classpath in the same directory as the IDM2Log4J.java file.


code: META-INF/MANIFEST.MF


Manifest-Version: 1.0


Save this as MANIFEST.MF, in a META-INF subdirectory of the directory where you saved IDM2Log4J.java.

Note that case is important here. These files must be named and saved exactly as shown.

To compile IDM2Log4J.java to IDM2Log4J.class:
javac -cp apache-log4j-1.2.15/log4j-1.2.15.jar IDM2Log4J.java

Then, to Create IDM2Log4J.jar:
jar cf IDM2Log4J.jar IDM2Log4J.class .project .classpath META-INF/MANIFEST.MF

The result should be a IDM2Log4J.jar file. This is one of two files you will need. The other is the configuration file.


code: IDMlog4j.properties


#### Using 2 appenders
# 1 for console output (stdout)
# 1 for logging to a file with automatic archive and rollover
log4j.rootCategory=DEBUG, fileOut, stdout

#### First appender (stdout)
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern layout for console (stdout).
log4j.appender.stdout.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss} %5p [%t] (%F:%L) - %m%n

#### Second appender (log file)
log4j.appender.fileOut =org.apache.log4j.RollingFileAppender
log4j.appender.fileOut.File=IDM.log

# Maximum size of log file for rollover
log4j.appender.fileOut.MaxFileSize=30000KB

# Maximum rolled over log files to keep
log4j.appender.fileOut.MaxBackupIndex=1

# Pattern layout for log file
log4j.appender.fileOut.layout=org.apache.log4j.PatternLayout
log4j.appender.fileOut.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss} %p %t %c - %m%n


Save this as IDM2Log4J.properties in the same directory as your IDM2Log4J.jar file. You can read up on the syntax and what all of these configuration parameters mean in the Log4J documentation. You can customize the message content and format with the ConversionPattern lines, and where the messages are routed to with the log4j.appender lines.

Step Two: Testing Your Work

Testing your work so far:
java -cp apache-log4j-1.2.15/log4j-1.2.15.jar:IDM2Log4J.jar IDM2Log4J

This should, if all went well, result in some messages written to the screen, and to a log file (IDM.log) in the current directory.

Now that’s interesting and helpful, but what we want is to send syslog messages. Before doing that, you need something that can receive them. Assuming you are working on a Linux system, you already have one (Syslog-NG). A quick change to its configuration:


code: Syslog-NG Configuration


Edit /etc/syslog-ng/syslog-ng.conf

        # 
        # uncomment to process log messages from network:
        #
        udp(ip("0.0.0.0") port(514));    ### Change this line - uncomment
		

and restart the daemon (/etc/init.d/syslog restart) to activate the change, and you have a syslog message receiver. You can watch it with: tail -F /var/log/messages

Now, change the IDM2Log4J.properties file to route messages to syslog:


code: IDMlog4j.properties


#### Using 3 appenders
# 1 for console output (stdout)
# 1 for logging to a file with automatic archive and rollover
# 1 for syslog messages output
log4j.rootCategory=DEBUG, fileOut, SYSLOG                               {CHANGE THIS LINE}

#### First appender (stdout)
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern layout for console (stdout).
log4j.appender.stdout.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss} %5p [%t] (%F:%L) - %m%n

#### Second appender (log file)
log4j.appender.fileOut =org.apache.log4j.RollingFileAppender
log4j.appender.fileOut.File=IDM.log

# Maximum size of log file for rollover
log4j.appender.fileOut.MaxFileSize=30000KB

# Maximum rolled over log files to keep
log4j.appender.fileOut.MaxBackupIndex=1

# Pattern layout for log file
log4j.appender.fileOut.layout=org.apache.log4j.PatternLayout
log4j.appender.fileOut.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss} %p %t %c - %m%n

#### Third appender (syslog)                                                        {ADD THIS BLOCK}
log4j.appender.SYSLOG=org.apache.log4j.net.SyslogAppender
log4j.appender.SYSLOG.syslogHost=localhost
log4j.appender.SYSLOG.layout=org.apache.log4j.PatternLayout
log4j.appender.SYSLOG.layout.ConversionPattern=%d{dd-MM-yyyy HH:mm:ss}  %-5p (%C:%M:%L) - %m%n
log4j.appender.SYSLOG.Facility=LOCAL1


And test it:
java -cp apache-log4j-1.2.15/log4j-1.2.15.jar:IDM2Log4J.jar IDM2Log4J

Again, if all went well, you should have seen several messages on your syslog receiver. Note that the test is the same, no compiled code had to be changed, only the configuration file. This is useful in its own right, but even more so when you want to use this class in various ways from within IDM policy, without having to change the Jar file each time you come up with a new idea that needs to be logged. Just change the properties file, and away you go.

Step Three: IDM Policy (DirXML Script)

Now that we have a working IDM2Log4J.jar file, and its configuration file, to use it from within Identity Manager is straightforward.

First, the log4j-1.2.15.jar and IDM2Log4J.jar files have to be added to the IDM server’s classpath.

NetWare: SYS:System\lib

Windows: c:\novell\nds\lib

Linux: /opt/novell/eDirectory/lib/dirxml/classes

And the IDM2Log4J.properties file has to be added to the IDM server’s DIB directory.

NetWare: SYS:_Netware

Windows: C:\novell\nds\dibfiles

Linux: /var/nds/data/dib

The first time a Java extention is used, eDirectory will load the code from the *.jar file. It remains resident for as long as eDirectory is running, and can be re-used from any driver that is running on this server. This allows the configuration via the properties file to remain in effect across multiple uses. The down side is that in order to change the code in the IDM2Log4J.jar file, you have to restart eDirectory. So we do not want to do that.

Next, to use this extention from policy, it must be declared so that IDM knows what you want to use, and what you want to call it. This is done via the “namespace” (“xmlns”) addition to a policy.


code: Policy Builder


<?xml version="1.0" encoding="UTF-8"?>
<policy xmlns:idmlog4j="http://www.novell.com/nxsl/java/IDM2Log4J"> 
 <rule>
  <description>Trigger Syslog Message</description>
  <conditions>
   <and>
    <if-operation mode="case" op="equal">trigger</if-operation>
   </and>
  </conditions>
  <actions>
   <do-set-local-variable name="SyslogMessage" scope="policy">
    <arg-string>
     <token-xpath expression="idmlog4j:log('IDMlog','IDMlog4j.properties','error','Test')"/>
    </arg-string>
   </do-set-local-variable>
  </actions>
 </rule>
</policy>


Then, once declared, you can call your Java extention function via XPath. In this case, to log a “Test” message, of severity “error”, via syslog to your syslog server:


code: Policy Builder


<?xml version="1.0" encoding="UTF-8"?>
<policy xmlns:idmlog4j="http://www.novell.com/nxsl/java/IDM2Log4J"> {highlight this line}
 <rule>
  <description>Trigger Syslog Message</description>
  <conditions>
   <and>
    <if-operation mode="case" op="equal">trigger</if-operation>
   </and>
  </conditions>
  <actions> 
   <do-set-local-variable name="SyslogMessage" scope="policy"> 
    <arg-string> 
     <token-xpath expression="idmlog4j:log('IDMlog','IDMlog4j.properties','error','Test')"/> 
    </arg-string> 
   </do-set-local-variable> 
  </actions> 
 </rule>
</policy>


The four parameters passed in to the idmlog4j:log expression are the logger name, the name of the configuration proproperties file, then the message severity and the message itself. The logger name is used, via the properties file, and can be part of the message sent out by Log4J. The properties file specifies the file to use for configuration. The severity levels, as described above, are Debug, Info, Warn, Error, and Fatal.

The message text can be anything you need. It will be modified, as specified in the IDM2Log4J.properties file, to include whatever other system information is specified in the ConversionPattern selected, and sent to the specified Receivers (syslog, files, etc.). You will want to standardize on what the message levels mean, and may want to even standardize on what sort of information should be included in the message text.

One note on the name of the properties file. On NetWare, the only tools that allow access to the SYS:_Netware directory do not support long file names. So the file name used must be in DOS 8.3 format like “IDMLOG4J.PRO”.

0 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 5 (0 votes, average: 0.00 out of 5)
You need to be a registered member to rate this post.
Loading...Loading...
Categories: Uncategorized

Disclaimer: As with everything else at NetIQ Cool Solutions, this content is definitely not supported by NetIQ, so Customer Support will not be able to help you if it has any adverse effect on your environment.  It just worked for at least one person, and perhaps it will be useful for you too.  Be sure to test in a non-production environment.

Leave a Reply

Leave a Comment

  • jhillyerd says:

    Thanks for the article, this is a good idea.

    I don’t think the .classpath and .project files are needed – those are used by Eclipse to manage a Java project, but not by the Java runtime itself.

By: dgersic
Jan 8, 2010
11:17 am
Reads:
1,606
Score:
Unrated