src.com.ibm.as400.util.servlet.AuthenticationServlet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400 Show documentation
Show all versions of jt400 Show documentation
The Open Source version of the IBM Toolbox for Java
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: AuthenticationServlet.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2000 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.util.servlet;
import java.util.Hashtable;
import java.util.Properties;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
import com.ibm.as400.access.Log; //$A2C
import com.ibm.as400.access.Trace;
import com.ibm.as400.util.BASE64Decoder;
/**
* AuthenticationServlet is an HttpServlet implementation that performs basic authentication for servlets.
* Subclasses should override the validateAuthority() method to perform the authentication. The bypassValidation()
* method can be overridden to authenticate only certain requests and the postValidation() method can be overridden
* for additional processing of the request after authenticating.
**/
public class AuthenticationServlet extends HttpServlet
{
static final long serialVersionUID = 3761917964251765027L;
/**
* The realm used for this servlet instance.
**/
private String realm_ = "localhost";
/**
* The actual name the user will see. This may be the same as realm in some cases. A realm of
* "localhost" may be meaningless to the user, while a realmDisplayName of "mysystem" may be more
* meaningful.
**/
private String realmDisplayName_;
/**
* Hashtable used to keep session data.
**/
private Hashtable sessionTable_ = new Hashtable();
/**
* The log to use for logging traces and errors. //$A2C
**/
private Log log_; //$A2C
// Handles loading the appropriate resource bundle
private static ResourceBundleLoader_s loader_; //$A1A
/**
* Constructs a default AuthenticationServlet object.
**/
public AuthenticationServlet()
{
super();
}
/**
* Constructs an AuthenticationServlet object with the specified user, password, and realm.
*
* @param user The user ID to use.
* @param password The password for this user ID.
* @param realm The realm, which refers to the system name.
**/
public AuthenticationServlet(String user, String password, String realm)
{
super();
setUser(user);
setPassword(password);
setRealm(realm);
}
/**
* Method to check to see if authentication should be performed. The default implementation returns false.
* Subclasses that wish to implement authentication based on the URL can override this method, interrogate
* the request object and determine if authentication should be performed.
*
* @param req The HttpServletRequest object for this request.
* @return true if authentication should not be performed.
*/
public boolean bypassAuthentication(HttpServletRequest req)
{
return false;
}
/**
* Get the log object used for tracing and error logging.
*
* @return The Log object to use for this servlet.
*/
public Log getLog()
{
return log_;
}
/**
* Retrieve the user that was used for the authentication.
*
* @return The authenticated user ID.
*/
public String getUser()
{
Thread currentThread = Thread.currentThread();
String threadId = currentThread.getName();
Properties p = (Properties)sessionTable_.get(threadId);
return p.getProperty("uid");
}
/**
* Retrieve the realm that was used for the authentication. For the IBM i system, the realm is the
* system name.
*
* @return The realm.
*/
public String getRealm()
{
return realm_;
}
/**
* Retrieve the Hashtable used to keep session data
*
* @return The session data.
*/
Hashtable getSessionData()
{
return sessionTable_;
}
/**
* Servlet initialization. The realm is initialized at this point to localhost. It can be overridden
* by the setRealm() method.
*
* @param config The servlet configuration.
* @exception ServletException A ServletException is thrown if a problem with the servlet occurs.
*/
public void init(ServletConfig config)
throws ServletException
{
log_ = new ServletEventLog(config);
super.init(config);
setRealm("localhost"); // @A7C
}
/**
* Log a message to the event log.
*
* @param msg The message to log.
*/
public void log(String msg)
{
if (log_ != null)
log_.log(msg);
}
/**
* Log an exception and message to the event log.
*
* @param e The exception to log.
* @param msg The message to log.
*/
public void log(Exception e, String msg)
{
if (log_ != null)
log_.log(msg, e);
}
/**
* Send the authentication response to the client.
*
* @param resp The HttpServletResponse object to use.
* @param realmDisplayName The realm name to be displayed by the client.
* @exception IOException An IOException is thrown if a communications error occurs.
*/
private void sendAuthenticationResponse(HttpServletResponse resp, String realmDisplayName)
throws IOException
{
log(loader_.substitute(loader_.getText("PROP_DESC_CHALLENGE"), new String[] {realmDisplayName_})); //$A1C
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
resp.setHeader("Www-authenticate", "Basic realm=\"" + realmDisplayName_ + "\"");
resp.setContentType("text/html");
}
/**
* Set the log object used for tracing and error logging.
*
* @param log The Log.
*/
public void setLog(Log log) //$A2C
{
if (log == null)
throw new NullPointerException("log");
log_ = log; //$A2C
}
/**
* Set the password. This method can be used to set the password to a default password after bypassing
* authentication.
*
* @param password The password to use.
*/
public void setPassword(String password)
{
if (password == null)
throw new NullPointerException("password");
Thread currentThread = Thread.currentThread();
String threadId = currentThread.getName();
Properties p = (Properties)sessionTable_.get(threadId);
if (p == null)
p = new Properties();
p.put("pw", password);
}
/**
* Override the default service() method for HttpServlet. Subclasses should not override this method unless
* necessary. If a subclass overrides this method, it should call super.service() or authentication would
* not occur for the servlet.
*
* @param req The HTTP servlet request.
* @param resp The HTTP servlet response.
* @exception ServletException A ServletException is thrown if a problem with the servlet occurs.
* @exception IOException An IOException is thrown if a communications error occurs.
**/
public void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
log(loader_.substitute(loader_.getText("PROP_DESC_SERVICE"), new String[] {req.getRemoteHost(), req.getRemoteAddr()})); //$A1C
// check to see if we should authenticate. Call bypassAuthentication() method, which can be overridden
// by subclasses to see if authentication should be performed. Default implementation is to authenticate
// all requests. Subclasses can override the method and interrogate the request object to determine
// if authentication is needed.
if (!bypassAuthentication(req))
{
// see if the header contained realm user ID and password
String uidpw = req.getHeader("Authorization");
if (uidpw != null)
{
int index = uidpw.indexOf(" ");
uidpw = uidpw.substring(index+1);
// now decode from base64
BASE64Decoder decoder = new BASE64Decoder();
byte[] buffer = decoder.decodeBuffer(uidpw);
String s = new String(buffer);
index = s.indexOf(":");
String uid, pw; // $A8C
// If a character causes the ':' and password which follows to be omitted from the // $A8A
// authoriztion header, then we need to ensure the password is set to an empty // $A8A
// string, which will allow the validateAuthority method to gracefully handle // $A8A
// an invalid uid/pwd string instead of generating exceptions. // $A8A
if (index == -1) // $A8A
{
uid = s; // $A8C
pw = ""; // $A8C
Trace.log(Trace.INFORMATION, "Missing ':' (colon) in authorization header."); // $A8A
} // $A8A
else // $A8A
{
uid = s.substring(0, index);
pw = s.substring(index+1);
}
try
{
log(loader_.substitute(loader_.getText("PROP_DESC_AUTHENTICATING"), new String[] {realm_, uid})); //$A1C
// $A5A
// The return from validateAuthority will tell if the caller wants to continue validation.
// When the caller overrides validateAuthority() they can then return false, which will
// allow them to display there own HTML error message/page in the browser instead of
// getting the default browser message (Error: 503... etc) when an exception occurs.
if (!validateAuthority(realm_, uid, pw)) //$A5C
return; //$A5A
Thread currentThread = Thread.currentThread();
String threadId = currentThread.getName();
Properties p = new Properties();
p.put("realm", realm_);
p.put("uid", uid);
p.put("pwd", pw);
sessionTable_.put(threadId, p);
log( loader_.substitute( loader_.getText( "PROP_DESC_AUTHENTICATED"), new String[ ] {realm_, uid})); //$A1C
//$A5A
// The return from postValidation will tell if the caller wants to continue validation.
// When the caller overrides postValidation() they can then return false, which will
// allow them to display there own HTML error message/page in the browser instead of
// getting the default browser message (Error: 503... etc) when an exception occurs.
if (!postValidation(req, resp)) //$A5C
return; //$A5A
super.service(req, resp);
sessionTable_.remove(threadId);
}
catch (SecurityException se)
{
log(loader_.substitute(loader_.getText("PROP_DESC_AUTHENTICATEFAILED"), new String[] {uid, se.getMessage()})); //$A1C $A6C
if (Trace.isTraceOn()) //$A6A
Trace.log(Trace.ERROR, se); //$A6A
sendAuthenticationResponse(resp, realmDisplayName_);
}
catch (Exception e)
{
log(loader_.substitute(loader_.getText("PROP_DESC_REQFAILED"), new String[] {uid, e.getMessage()})); //$A1C $A6C
if (Trace.isTraceOn()) //$A6A
Trace.log(Trace.ERROR, e); //$A6A
if (e instanceof IOException) //$A4A
throw (IOException)e; //$A4A
else if (e instanceof ServletException) //$A4A
throw (ServletException)e; //$A4A
else if (e instanceof RuntimeException) // @A4C
throw (RuntimeException)e; // @A4C
else //$A4C
throw new ServletException(e.getMessage()); // @A4C
}
log(loader_.substitute(loader_.getText("PROP_DESC_REQCOMPLETED"), new String[] {req.getRemoteHost(), req.getRemoteAddr()})); //$A1C
return;
}
// respond with realm challenge
sendAuthenticationResponse(resp, realmDisplayName_);
}
else
{
super.service(req, resp);
}
}
/**
* Set the realm that will be used for the authentication. For the IBM i system, the realm is the
* system name.
*
* @param realm The realm, which refers to the system name.
**/
public void setRealm(String realm)
{
if (realm == null)
throw new NullPointerException("realm");
if (realm.equalsIgnoreCase("localhost"))
{
try
{
InetAddress local = InetAddress.getLocalHost();
realmDisplayName_ = local.getHostName();
realm_ = realmDisplayName_; // @A7A
}
catch (UnknownHostException e)
{
log(loader_.getText("PROP_DESC_REALMFAILED")); //$A1C $A6C
if (Trace.isTraceOn()) //$A6A
Trace.log(Trace.ERROR, e); //$A6A
realm_ = realm; // @A7A
realmDisplayName_ = realm;
}
}
else
{
realm_ = realm; // @A7A
realmDisplayName_ = realm;
}
}
/**
* Set the user ID. This method can be used to set the user ID to a default user after bypassing
* authenticaiton.
*
* @param user The user ID to use.
**/
public void setUser(String user)
{
if (user == null)
throw new NullPointerException("user");
Thread currentThread = Thread.currentThread();
String threadId = currentThread.getName();
Properties p = (Properties)sessionTable_.get(threadId);
if (p == null)
p = new Properties();
p.put("uid", user);
}
/**
* Method used to validate. The default implementation does nothing. Subclasses should override this method
* and implement appropriate validation scheme.
*
* @param realm The realm to validate against.
* @param uid The user ID to use for validation.
* @param pw The password to use for validation.
*
* @return true if the servlet should continue authenticating; false otherwise. The default is true;
*
* @exception SecurityException This exception should be thrown if validation fails.
* @exception IOException This exception should be thrown if a communication error occurs during validation.
**/
public boolean validateAuthority(String realm, String uid, String pw) //$A5C
throws SecurityException, IOException
{
return true;
}
/**
* Method called after validation has occured. The default implementation does nothing.
* Subclasses should override this method to continue processing the request.
*
* @param req The HTTP servlet request.
* @param resp The HTTP servlet response.
*
* @return true if the servlet should continue authenticating; false otherwise. The default is true;
*
* @exception ServletException A ServletException is thrown if a problem with the servlet occurs.
* @exception IOException An IOException is thrown if a communications error occurs.
**/
public boolean postValidation(HttpServletRequest req, HttpServletResponse resp) //$A3 //$A5C
throws ServletException, IOException
{
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy