diff --git a/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java index 2c592010dd..12704b7aaf 100644 --- a/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java +++ b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java @@ -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. - * + * *
* 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; diff --git a/changelog.txt b/changelog.txt index 98d1560cc9..369f4875e2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -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) ----------------------------------- diff --git a/core/src/main/java/org/acegisecurity/AcegiSecurityException.java b/core/src/main/java/org/acegisecurity/AcegiSecurityException.java index c17d5b691a..af7f7d43f6 100644 --- a/core/src/main/java/org/acegisecurity/AcegiSecurityException.java +++ b/core/src/main/java/org/acegisecurity/AcegiSecurityException.java @@ -21,7 +21,7 @@ import org.springframework.core.NestedRuntimeException; /** * Abstract superclass for all exceptions thrown in the security package and * subpackages. - * + * *
* Note that this is a runtime (unchecked) exception. Security exceptions are * usually fatal; there is no reason for them to be checked. diff --git a/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java b/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java index c6d7b24dfc..86c6307cdb 100644 --- a/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java +++ b/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java @@ -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}. * - *
- * This filter is necessary because it provides an application context
- * environment for the FilterSecurityInterceptor instance.
+ *
+ * This filter is necessary because it provides the bridge between incoming
+ * requests and the FilterSecurityInterceptor instance.
*
+ *
* If a {@link AuthenticationException} is detected, the filter will redirect
* to the loginFormUrl. This allows common handling of
* authentication failures originating from any subclass of {@link
@@ -60,33 +64,55 @@ import javax.servlet.http.HttpServletResponse;
* security interceptor.
*
+ *
+ * This filter works with a FilterSecurityInterceptor 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 FilterSecurityInterceptor instance. In the case
+ * where it is desireable for this filter to instantiate its own
+ * ApplicationContext instance from which to obtain the
+ * FilterSecurityInterceptor, the location of the config for this
+ * context may be specified with the optional
+ * contextConfigLocation init param.
+ *
* To use this filter, it is necessary to specify the following filter * initialization parameters: + *
* *appContextLocation indicates the path to an application context
- * that contains the FilterSecurityInterceptor.
- * loginFormUrl indicates the URL that should be used for
* redirection if an AuthenticationException is detected.
* contextConfigLocation (optional, normally not used), indicates
+ * the path to an application context that contains a properly configured
+ * FilterSecurityInterceptor. If not specified, {@link
+ * WebApplicationContextUtils#getWebApplicationContext(ServletContext sc)}
+ * will be used to obtain the context.
+ * AuthenticationException 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);
diff --git a/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilter.java
index c9d4185e59..ba08b40d3e 100644
--- a/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilter.java
+++ b/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilter.java
@@ -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}.
*
*
- * + *
* 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. *
* - *+ *
* If authentication fails, the AuthenticationException will be
* placed into the HttpSession with the attribute defined by
* {@link #ACEGI_SECURITY_LAST_EXCEPTION_KEY}.
*
+ *
+ * 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
+ * appContextLocation init param.
+ *
* To use this filter, it is necessary to specify the following filter * initialization parameters: + *
* *appContextLocation indicates the path to an application context
- * that contains an {@link AuthenticationManager} that should be used to
- * process each authentication request.
- * defaultTargetUrl indicates the URL that should be used for
* redirection if the HttpSession 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
* /j_acegi_security_check.
* appContextLocation (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.
+ * /j_acegi_security_check)
*/
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);
diff --git a/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java b/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java
index a32dcd3700..1aacc9364a 100644
--- a/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java
+++ b/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java
@@ -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."));
}
}
diff --git a/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterTests.java b/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterTests.java
index 9b024cce48..0992b664cc 100644
--- a/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterTests.java
+++ b/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterTests.java
@@ -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."));
}
}
diff --git a/test/.cvsignore b/test/.cvsignore
new file mode 100644
index 0000000000..91696b3e12
--- /dev/null
+++ b/test/.cvsignore
@@ -0,0 +1,2 @@
+acegisecuritytest.properties
+acegisecuritytest.script
diff --git a/upgrade-04-05.txt b/upgrade-04-05.txt
new file mode 100644
index 0000000000..2a8c240054
--- /dev/null
+++ b/upgrade-04-05.txt
@@ -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$