/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2004 Danet GmbH (www.danet.de), GS-AN.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: LoginFilter.java 1607 2006-09-29 12:32:13Z drmlipp $
*
* $Log$
* Revision 1.1.1.1 2004/08/18 15:17:35 drmlipp
* Update to 1.2
*
* Revision 1.1 2004/03/12 10:42:47 lipp
* Added.
*
*/
package de.danet.an.util.web;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextOutputCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* This filter performs an automatic logon before the next filter in
* the chain is called and a logout after the next filter has
* completed.<P>
*
* The filter can be configured using the following parameters:
* <dl>
* <dt><code>ApplicationPolicy</code></dt>
* <dd>the application policy to use. For JBoss, this must be one of the
* policies defined in
* <code>$JBOSS_HOME/server/<em>instance</em>/conf/login-config.xml</code>.
* The default is <code>client-login</code>.
* </dd>
* <dt><code>UserName</code></dt>
* <dd>the user name to use for login</dd>
* <dt><code>Password</code></dt>
* <dd>the password to use for login</dd>
* </dl><P>
*
* This implementation currently supports JBoss and WLS 8.1.<P>
*/
public class LoginFilter implements Filter {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory.getLog
(LoginFilter.class);
/**
* Simple login context for authentication.
*/
private static class LoginFilterLoginContext extends LoginContext {
private static class CBH implements CallbackHandler {
private String userName = null;
private String password = null;
public CBH (String userName, String password) {
this.userName = userName;
this.password = password;
}
public void handle (Callback[] callbacks)
throws UnsupportedCallbackException, IOException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof TextOutputCallback) {
// display the message according to the specified type
TextOutputCallback toc
= (TextOutputCallback)callbacks[i];
switch (toc.getMessageType()) {
case TextOutputCallback.INFORMATION:
System.err.println(toc.getMessage());
break;
case TextOutputCallback.ERROR:
System.err.println("ERROR: " + toc.getMessage());
break;
case TextOutputCallback.WARNING:
System.err.println("WARNING: " + toc.getMessage());
break;
default:
throw new IOException
("Unsupported message type: "
+ toc.getMessageType());
}
} else if (callbacks[i] instanceof NameCallback) {
// prompt the user for a username
NameCallback nc = (NameCallback)callbacks[i];
nc.setName(userName);
} else if (callbacks[i] instanceof PasswordCallback) {
// prompt the user for sensitive information
PasswordCallback pc = (PasswordCallback)callbacks[i];
pc.setPassword(password.toCharArray());
} else if (callbacks[i].getClass().getName().equals
("weblogic.security.auth.callback.URLCallback")) {
} else {
throw new UnsupportedCallbackException
(callbacks[i], "Unrecognized Callback \""
+ callbacks[i].getClass().getName() + "\"");
}
}
}
}
public LoginFilterLoginContext
(String applicationPolicy, String userName, String password)
throws LoginException {
super (applicationPolicy, new CBH(userName, password));
}
}
/** The WLS security class. Indicates if WLS security is used. */
private Class wlsSec = null;
/** The context used for the login and logout operations */
private LoginContext loginContext;
/**
* Initialize the filter.
*
* @param filterConfig the filter configuration information
* @throws ServletException if the login context cannot be created
*/
public void init(FilterConfig filterConfig)
throws ServletException {
// first, find out if we have WLS security
try {
wlsSec = Thread.currentThread().getContextClassLoader()
.loadClass("weblogic.security.Security");
} catch (ClassNotFoundException e) {
// OK, not WLS client
logger.debug ("No WLS security class, not using WLS security");
}
// now get the parameters
String applicationPolicy
= filterConfig.getInitParameter("ApplicationPolicy");
if (applicationPolicy == null) {
applicationPolicy = "client-login";
}
String userName = filterConfig.getInitParameter("UserName");
String password = filterConfig.getInitParameter("Password");
if (logger.isDebugEnabled ()) {
logger.debug ("Configured to use application policy \""
+ applicationPolicy + "\", user name \""
+ userName + "\" and "
+ (password == null ? " no password."
: "a (non-disclosed) password."));
}
// finally, create login context
try {
loginContext = new LoginFilterLoginContext
(applicationPolicy, userName, password);
} catch (LoginException e) {
throw new ServletException
("Cannot create LoginContext: " + e.getMessage(), e);
}
}
/**
* Do nothing.
*/
public void destroy() {}
/**
* Perform a login, call the next filter on the filter chain and
* perform a logout.
*
* @param request the request
* @param response the response
* @param chain the filter chain
* @throws IOException IOException
* @throws ServletException ServletException
*/
public void doFilter
(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
loginContext.login ();
} catch (LoginException e) {
throw new ServletException ("Cannot login: " + e.getMessage(), e);
}
try {
if (wlsSec != null) {
// Use WLS security. Use reflection to avoid code
// dependency on WLS
try {
Class[] ats = new Class[]
{ Subject.class, PrivilegedAction.class };
Method m = wlsSec.getMethod ("runAs", ats);
final FilterChain chainArg = chain;
final ServletRequest reqArg = request;
final ServletResponse resArg = response;
Object[] args = new Object[] {
loginContext.getSubject(),
new PrivilegedExceptionAction () {
public Object run () throws Exception {
chainArg.doFilter(reqArg, resArg);
return null;
}
} };
m.invoke (null, args);
} catch (NoSuchMethodException e) {
logger.error (e.getMessage (), e);
throw new IllegalStateException (e.getMessage());
} catch (SecurityException e) {
logger.error (e.getMessage (), e);
throw new IllegalStateException (e.getMessage());
} catch (IllegalAccessException e) {
logger.error (e.getMessage (), e);
throw new IllegalStateException (e.getMessage());
} catch (InvocationTargetException e) {
if (e.getTargetException ()
instanceof PrivilegedActionException) {
PrivilegedActionException pe
= (PrivilegedActionException)e.getTargetException();
if (pe.getException () instanceof IOException) {
throw (IOException)pe.getException ();
}
if (pe.getException() instanceof ServletException) {
throw (ServletException)pe.getException ();
}
}
logger.error (e.getMessage (), e);
throw new IllegalStateException (e.getMessage());
}
} else {
// Use JBoss security.
chain.doFilter(request, response);
}
} finally {
try {
loginContext.logout ();
} catch (LoginException e) {
throw new ServletException
("Cannot logout: " + e.getMessage(), e);
}
}
}
}