Authenticating users with Active Directory
This article describes a simple Java Extension that manages the HTTP Basic Authentication process and validates the supplied username and password against an Active Directory database. It shows how to use Initialization Parameters to provide configuration to an extension, and how authentication results can be cached to reduce the load on the Active Directory server:
Step 1: The Java ExtensionUse Eclipse or an alternative Java IDE to build an extension named '
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.zeus.ZXTMServlet.ZXTMHttpServletRequest;
public class LdapAuthenticate extends HttpServlet {
private static final long serialVersionUID = 1L;
private String dirServer;
private String realm;
public void init( ServletConfig config) throws ServletException {
super.init( config );
dirServer = config.getInitParameter( "DB" );
realm = config.getInitParameter( "Realm" );
if( dirServer == null ) throw new ServletException( "No DB configured" );
if( realm == null ) realm = "Secure site";
}
public void doGet( HttpServletRequest req, HttpServletResponse res )
throws ServletException, IOException
{
try {
ZXTMHttpServletRequest zreq = (ZXTMHttpServletRequest)req;
String[] userPass = zreq.getRemoteUserAndPassword();
if( userPass == null ) throw new Exception( "No Authentication details" );
Hashtable<String, String> env = new Hashtable<String, String>();
env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put( Context.PROVIDER_URL, "LDAP://" + dirServer );
env.put( Context.SECURITY_AUTHENTICATION, "DIGEST-MD5" );
env.put( Context.SECURITY_PRINCIPAL, userPass[0] );
env.put( Context.SECURITY_CREDENTIALS, userPass[1] );
DirContext ctx = new InitialDirContext( env );
ctx.close();
// No exceptions thrown... must have been successful ;-)
return;
} catch( Exception e ) {
res.setHeader( "WWW-Authenticate", "Basic realm=\"" + realm + "\"" );
res.setHeader( "Content-Type", "text/html" );
res.setStatus( 401 );
String message =
"<html>" +
"<head><title>Unauthorized</title></head>" +
"<body>" +
"<h2>Unauthorized - please log in</h2>" +
"<p>Please log in with your system username and password</p>" +
"<p>Error: " + e.toString() + "</p>" +
"</body>" +
"</html>";
PrintWriter out = res.getWriter();
out.println( message );
}
}
public void doPost( HttpServletRequest req, HttpServletResponse res )
throws ServletException, IOException
{
doGet( req, res );
}
}
Alternatively, download the compiled ' For more information on building Java Extensions, see the "Watermarking Images with Java Extensions" article, and the ZXTM 5.0 Java Development Guide. Configuring the Java ExtensionUpload the
These parameters are read when the extension is initialized, which occurs the first time the extension is used by ZXTM:
public void init( ServletConfig config) throws ServletException {
super.init( config );
dirServer = config.getInitParameter( "DB" );
realm = config.getInitParameter( "Realm" );
if( dirServer == null ) throw new ServletException( "No DB configured" );
if( realm == null ) realm = "Secure site";
}
If you change the value of one of these parameters, use the 'Force Reload' option in the ZXTM Admin Server to unload and reload this extension. Either use the auto-generated rule, or create a new TrafficScript rule to call the extension on every request to an HTTP virtual server: java.run( "LdapAuthenticate" ); Testing the Java ExtensionWhen you try to access the web site through ZXTM, you will be prompted for a username and password; the LdapAuthenticate extension checks that the username and password can bind to the configured Active Directory database, and refuses access if not:
If you are unable to log in, cancel the prompt dialog box to see the error reported by the Java extension. In the following case, the extension was misconfigured; it could not resolve the name of the database server provided in the '
Step 2: Caching the Authentication ResultsCaching the Authentication response from the Java extension will improve the performance of the web site and reduce the load on the database server. You can modify the TrafficScript rule that calls the extension so that it records successful logins, caching them for a period of time. The following rule uses the
$auth = http.getHeader( "Authorization" );
if( data.get( $auth ) < sys.time() ) {
data.remove( $auth );
java.run( "LdapAuthenticate" );
# if we got here, we were authenticated.
# Cache this information for 600 seconds
data.set( $auth, sys.time()+600 );
}
ConclusionThis example shows how you can apply a consistent access policy across your application infrastructure, even if your service is made up of several different types of back-end applications, some of which may not support your desired authentication method.
Owen Garrett
[Zeus Dev Team] 22 May 2008
|
Recent Articles
Other Resources
|

A very common requirement for intranet and extranet applications is the need to authenticate users against an Active Directory (or LDAP) database. The Java Extension in this article describes how to do exactly that.




