change AuthenticationProcessingFilter and SecurityEnforcementFilter to use Spring's WebApplicationContextUtils by defualt to find their config context.

This commit is contained in:
Colin Sampaleanu 2004-04-09 02:44:17 +00:00
parent 7bb4f14849
commit 6c26e79a0f
9 changed files with 185 additions and 66 deletions

View File

@ -12,6 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.adapters.jboss;
import net.sf.acegisecurity.Authentication;
@ -44,7 +45,7 @@ import javax.security.auth.login.LoginException;
/**
* Adapter to enable JBoss to authenticate via the Acegi Security System for
* Spring.
*
*
* <p>
* Returns a {@link PrincipalAcegiUserToken} to JBoss' authentication system,
* which is subsequently available from
@ -55,11 +56,15 @@ import javax.security.auth.login.LoginException;
* @version $Id$
*/
public class JbossAcegiLoginModule extends AbstractServerLoginModule {
//~ Instance fields ========================================================
private AuthenticationManager authenticationManager;
private Principal identity;
private String key;
private char[] credential;
//~ Methods ================================================================
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
super.initialize(subject, callbackHandler, sharedState, options);
@ -78,8 +83,8 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule {
}
if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
throw new IllegalArgumentException("Cannot locate " +
appContextLocation);
throw new IllegalArgumentException("Cannot locate "
+ appContextLocation);
}
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(appContextLocation);
@ -104,8 +109,8 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule {
if ((username == null) && (password == null)) {
identity = null;
super.log.trace("Authenticating as unauthenticatedIdentity=" +
identity);
super.log.trace("Authenticating as unauthenticatedIdentity="
+ identity);
}
if (username == null) {
@ -145,8 +150,8 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule {
}
super.loginOk = true;
super.log.trace("User '" + identity + "' authenticated, loginOk=" +
loginOk);
super.log.trace("User '" + identity + "' authenticated, loginOk="
+ loginOk);
return true;
}
@ -157,7 +162,7 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule {
protected Group[] getRoleSets() throws LoginException {
SimpleGroup roles = new SimpleGroup("Roles");
Group[] roleSets = { roles };
Group[] roleSets = {roles};
if (this.identity instanceof Authentication) {
Authentication user = (Authentication) this.identity;
@ -172,17 +177,17 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule {
}
protected String[] getUsernameAndPassword() throws LoginException {
String[] info = { null, null };
String[] info = {null, null};
// prompt for a username and password
if (callbackHandler == null) {
throw new LoginException("Error: no CallbackHandler available " +
"to collect authentication information");
throw new LoginException("Error: no CallbackHandler available "
+ "to collect authentication information");
}
NameCallback nc = new NameCallback("User name: ", "guest");
PasswordCallback pc = new PasswordCallback("Password: ", false);
Callback[] callbacks = { nc, pc };
Callback[] callbacks = {nc, pc};
String username = null;
String password = null;
@ -202,8 +207,8 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule {
} catch (java.io.IOException ioe) {
throw new LoginException(ioe.toString());
} catch (UnsupportedCallbackException uce) {
throw new LoginException("CallbackHandler does not support: " +
uce.getCallback());
throw new LoginException("CallbackHandler does not support: "
+ uce.getCallback());
}
info[0] = username;

View File

@ -1,3 +1,10 @@
Changes in version 0.5 (2004-xx-xx)
-----------------------------------
* AuthenticationProcessingFilter by default finds configuration context using Spring's WebApplicationContextUtils.getWebApplicationContext()
* AuthenticationProcessingFilter context may optionally be specified with 'contextConfigLocation' param (was previously 'appContextLocation')
* SecurityEnforcementFilter by default finds configuration context using Spring's WebApplicationContextUtils.getWebApplicationContext()
* SecurityEnforcementFilter context may optionally be specified with 'contextConfigLocation' param (was previously 'appContextLocation')
Changes in version 0.4 (2004-04-03)
-----------------------------------

View File

@ -21,7 +21,7 @@ import org.springframework.core.NestedRuntimeException;
/**
* Abstract superclass for all exceptions thrown in the security package and
* subpackages.
*
*
* <p>
* Note that this is a runtime (unchecked) exception. Security exceptions are
* usually fatal; there is no reason for them to be checked.

View File

@ -22,8 +22,12 @@ import net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import java.io.IOException;
import java.util.Map;
@ -41,12 +45,12 @@ import javax.servlet.http.HttpServletResponse;
/**
* Wraps requests to the {@link FilterSecurityInterceptor}.
*
* <P>
* This filter is necessary because it provides an application context
* environment for the <code>FilterSecurityInterceptor</code> instance.
* <p>
* This filter is necessary because it provides the bridge between incoming
* requests and the <code>FilterSecurityInterceptor</code> instance.
* </p>
*
* <P>
* <p>
* If a {@link AuthenticationException} is detected, the filter will redirect
* to the <code>loginFormUrl</code>. This allows common handling of
* authentication failures originating from any subclass of {@link
@ -60,33 +64,55 @@ import javax.servlet.http.HttpServletResponse;
* security interceptor.
* </p>
*
* <P>
* <p>
* This filter works with a <code>FilterSecurityInterceptor</code> instance. By
* default, at init time, the filter will use Spring's {@link
* WebApplicationContextUtils#getWebApplicationContext(ServletContext sc)}
* method to obtain an ApplicationContext instance, inside which must be a
* configured <code>FilterSecurityInterceptor</code> instance. In the case
* where it is desireable for this filter to instantiate its own
* ApplicationContext instance from which to obtain the
* <code>FilterSecurityInterceptor</code>, the location of the config for this
* context may be specified with the optional
* <code>contextConfigLocation</code> init param.
* </p>
*
* <p>
* To use this filter, it is necessary to specify the following filter
* initialization parameters:
* </p>
*
* <ul>
* <li>
* <code>appContextLocation</code> indicates the path to an application context
* that contains the <code>FilterSecurityInterceptor</code>.
* </li>
* <li>
* <code>loginFormUrl</code> indicates the URL that should be used for
* redirection if an <code>AuthenticationException</code> is detected.
* </li>
* <li>
* <code>contextConfigLocation</code> (optional, normally not used), indicates
* the path to an application context that contains a properly configured
* <code>FilterSecurityInterceptor</code>. If not specified, {@link
* WebApplicationContextUtils#getWebApplicationContext(ServletContext sc)}
* will be used to obtain the context.
* </li>
* </ul>
* </p>
*
*
* @author Ben Alex
* @author colin sampaleanu
* @version $Id$
*/
public class SecurityEnforcementFilter implements Filter {
//~ Static fields/initializers =============================================
/**
* Name of (optional) servlet filter parameter that can specify the config
* location for a new ApplicationContext used to config this filter.
*/
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
private static final Log logger = LogFactory.getLog(SecurityEnforcementFilter.class);
//~ Instance fields ========================================================
protected ClassPathXmlApplicationContext ctx;
protected FilterSecurityInterceptor securityInterceptor;
/**
@ -94,11 +120,15 @@ public class SecurityEnforcementFilter implements Filter {
* <code>AuthenticationException</code> is detected.
*/
protected String loginFormUrl;
private ApplicationContext ctx;
private boolean ourContext = false;
//~ Methods ================================================================
public void destroy() {
ctx.close();
if (ourContext && ctx instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) ctx).close();
}
}
public void doFilter(ServletRequest request, ServletResponse response,
@ -145,15 +175,15 @@ public class SecurityEnforcementFilter implements Filter {
}
public void init(FilterConfig filterConfig) throws ServletException {
String appContextLocation = filterConfig.getInitParameter(
"appContextLocation");
String appContextLocation = filterConfig.getInitParameter(CONFIG_LOCATION_PARAM);
if ((appContextLocation == null) || "".equals(appContextLocation)) {
throw new ServletException("appContextLocation must be specified");
}
if ((appContextLocation != null) && (appContextLocation.length() > 0)) {
ourContext = true;
if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
throw new ServletException("Cannot locate " + appContextLocation);
if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
throw new ServletException("Cannot locate "
+ appContextLocation);
}
}
loginFormUrl = filterConfig.getInitParameter("loginFormUrl");
@ -162,7 +192,21 @@ public class SecurityEnforcementFilter implements Filter {
throw new ServletException("loginFormUrl must be specified");
}
ctx = new ClassPathXmlApplicationContext(appContextLocation);
try {
if (!ourContext) {
ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(filterConfig
.getServletContext());
} else {
ctx = new ClassPathXmlApplicationContext(appContextLocation);
}
} catch (RuntimeException e) {
throw new ServletException(
"Error obtaining/creating ApplicationContext for config. Must be stored in ServletContext, or optionally '"
+ CONFIG_LOCATION_PARAM
+ "' param may be used to allow creation of new context by this filter. See root error for additional details",
e);
}
Map beans = ctx.getBeansOfType(FilterSecurityInterceptor.class, true,
true);

View File

@ -23,8 +23,12 @@ import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import java.io.IOException;
import java.util.Map;
@ -52,30 +56,39 @@ import javax.servlet.http.HttpServletResponse;
* HttpSessionIntegrationFilter#ACEGI_SECURITY_AUTHENTICATION_KEY}.
* </p>
*
* <P>
* <p>
* Login forms must present two parameters to this filter: a username and
* password. The filter will process the login against the authentication
* environment that was configured from a Spring application context defined
* in the filter initialization.
* </p>
*
* <P>
* <p>
* If authentication fails, the <code>AuthenticationException</code> will be
* placed into the <code>HttpSession</code> with the attribute defined by
* {@link #ACEGI_SECURITY_LAST_EXCEPTION_KEY}.
* </p>
*
* <P>
* <p>
* This filter works with an {@link AuthenticationManager} which is used to
* process each authentication request. By default, at init time, the filter
* will use Spring's {@link
* WebApplicationContextUtils#getWebApplicationContext(ServletContext sc)}
* method to obtain an ApplicationContext instance, inside which must be a
* configured AuthenticationManager instance. In the case where it is
* desireable for this filter to instantiate its own ApplicationContext
* instance from which to obtain the AuthenticationManager, the location of
* the config for this context may be specified with the optional
* <code>appContextLocation</code> init param.
* </p>
*
* <p>
* To use this filter, it is necessary to specify the following filter
* initialization parameters:
* </p>
*
* <ul>
* <li>
* <code>appContextLocation</code> indicates the path to an application context
* that contains an {@link AuthenticationManager} that should be used to
* process each authentication request.
* </li>
* <li>
* <code>defaultTargetUrl</code> indicates the URL that should be used for
* redirection if the <code>HttpSession</code> attribute named {@link
* #ACEGI_SECURITY_TARGET_URL_KEY} does not indicate the target URL once
@ -91,15 +104,29 @@ import javax.servlet.http.HttpServletResponse;
* respond to. This parameter is optional, and defaults to
* <code>/j_acegi_security_check</code>.
* </li>
* <li>
* <code>appContextLocation</code> (optional, normally not used), indicates the
* path to an application context that contains an {@link
* AuthenticationManager} which should be used to process each authentication
* request. If not specified, {@link
* WebApplicationContextUtils#getWebApplicationContext(ServletContext sc)}
* will be used to obtain the context.
* </li>
* </ul>
* </p>
*
*
* @author Ben Alex
* @author colin sampaleanu
* @version $Id$
*/
public class AuthenticationProcessingFilter implements Filter {
//~ Static fields/initializers =============================================
/**
* Name of (optional) servlet filter parameter that can specify the config
* location for a new ApplicationContext used to config this filter.
*/
public static final String CONFIG_LOCATION_PARAM = "appContextLocation";
public static final String ACEGI_SECURITY_TARGET_URL_KEY = "ACEGI_SECURITY_TARGET_URL";
public static final String ACEGI_SECURITY_FORM_USERNAME_KEY = "j_username";
public static final String ACEGI_SECURITY_FORM_PASSWORD_KEY = "j_password";
@ -108,8 +135,8 @@ public class AuthenticationProcessingFilter implements Filter {
//~ Instance fields ========================================================
private ApplicationContext ctx;
private AuthenticationManager authenticationManager;
private ClassPathXmlApplicationContext ctx;
/** Where to redirect the browser to if authentication fails */
private String authenticationFailureUrl;
@ -125,11 +152,14 @@ public class AuthenticationProcessingFilter implements Filter {
* <code>/j_acegi_security_check</code>)
*/
private String filterProcessesUrl;
private boolean ourContext = false;
//~ Methods ================================================================
public void destroy() {
ctx.close();
if (ourContext && ctx instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) ctx).close();
}
}
public void doFilter(ServletRequest request, ServletResponse response,
@ -216,15 +246,15 @@ public class AuthenticationProcessingFilter implements Filter {
}
public void init(FilterConfig filterConfig) throws ServletException {
String appContextLocation = filterConfig.getInitParameter(
"appContextLocation");
String appContextLocation = filterConfig.getInitParameter(CONFIG_LOCATION_PARAM);
if ((appContextLocation == null) || "".equals(appContextLocation)) {
throw new ServletException("appContextLocation must be specified");
}
if ((appContextLocation != null) && (appContextLocation.length() > 0)) {
ourContext = true;
if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
throw new ServletException("Cannot locate " + appContextLocation);
if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
throw new ServletException("Cannot locate "
+ appContextLocation);
}
}
defaultTargetUrl = filterConfig.getInitParameter("defaultTargetUrl");
@ -248,7 +278,21 @@ public class AuthenticationProcessingFilter implements Filter {
filterProcessesUrl = "/j_acegi_security_check";
}
ctx = new ClassPathXmlApplicationContext(appContextLocation);
try {
if (!ourContext) {
ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(filterConfig
.getServletContext());
} else {
ctx = new ClassPathXmlApplicationContext(appContextLocation);
}
} catch (RuntimeException e) {
throw new ServletException(
"Error obtaining/creating ApplicationContext for config. Must be stored in ServletContext, or optionally '"
+ CONFIG_LOCATION_PARAM
+ "' param may be used to allow creation of new context by this filter. See root error for additional details",
e);
}
Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);

View File

@ -150,8 +150,7 @@ public class SecurityEnforcementFilterTests extends TestCase {
}
}
public void testStartupDetectsMissingAppContextLocation()
throws Exception {
public void testStartupDetectsMissingAppContext() throws Exception {
MockFilterConfig config = new MockFilterConfig();
config.setInitParmeter("loginFormUrl", "/login.jsp");
@ -161,8 +160,7 @@ public class SecurityEnforcementFilterTests extends TestCase {
filter.init(config);
fail("Should have thrown ServletException");
} catch (ServletException expected) {
assertEquals("appContextLocation must be specified",
expected.getMessage());
assertTrue(expected.getMessage().startsWith("Error obtaining/creating ApplicationContext for config."));
}
config.setInitParmeter("appContextLocation", "");
@ -171,8 +169,7 @@ public class SecurityEnforcementFilterTests extends TestCase {
filter.init(config);
fail("Should have thrown ServletException");
} catch (ServletException expected) {
assertEquals("appContextLocation must be specified",
expected.getMessage());
assertTrue(expected.getMessage().startsWith("Error obtaining/creating ApplicationContext for config."));
}
}

View File

@ -287,8 +287,7 @@ public class AuthenticationProcessingFilterTests extends TestCase {
}
}
public void testStartupDetectsMissingAppContextLocation()
throws Exception {
public void testStartupDetectsMissingAppContext() throws Exception {
MockFilterConfig config = new MockFilterConfig();
config.setInitParmeter("defaultTargetUrl", "/");
config.setInitParmeter("authenticationFailureUrl", "/failed.jsp");
@ -299,8 +298,7 @@ public class AuthenticationProcessingFilterTests extends TestCase {
filter.init(config);
fail("Should have thrown ServletException");
} catch (ServletException expected) {
assertEquals("appContextLocation must be specified",
expected.getMessage());
assertTrue(expected.getMessage().startsWith("Error obtaining/creating ApplicationContext for config."));
}
config.setInitParmeter("appContextLocation", "");
@ -309,8 +307,7 @@ public class AuthenticationProcessingFilterTests extends TestCase {
filter.init(config);
fail("Should have thrown ServletException");
} catch (ServletException expected) {
assertEquals("appContextLocation must be specified",
expected.getMessage());
assertTrue(expected.getMessage().startsWith("Error obtaining/creating ApplicationContext for config."));
}
}

2
test/.cvsignore Normal file
View File

@ -0,0 +1,2 @@
acegisecuritytest.properties
acegisecuritytest.script

23
upgrade-04-05.txt Normal file
View File

@ -0,0 +1,23 @@
===============================================================================
ACEGI SECURITY SYSTEM FOR SPRING - UPGRADING FROM 0.4 TO 0.5
===============================================================================
Unfortunately, changes to the API and package locations were required. The
following should help most casual users of the project update their
applications:
- By default, AuthenticationProcessingFilter and SecurityEnforcementFilter now
use Spring's WebApplicationContextUtils.getApplicationContext to load the
ApplicationContext in which their respective configs may be found. Ideally,
move your configuration for these filters from the separate contexts you were
using before, to the main context used by your webapp. Alternately, the old
mechanism of having the filter load its own specific context is still
supported, but the param specifying the location of this context has been
changed to match the equivalent param as used by Spring's ContextLoader class.
If you do still want to use this approach, just rename your param from
'appContextLocation' to 'contextConfigLocation'.
We hope you find the new features useful in your projects.
$Id$