Преглед на файлове

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

Colin Sampaleanu преди 21 години
родител
ревизия
6c26e79a0f

+ 19 - 14
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.
- *
+ * 
  * <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;

+ 7 - 0
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)
 -----------------------------------
 

+ 1 - 1
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.
- *
+ * 
  * <p>
  * Note that this is a runtime (unchecked) exception. Security exceptions are
  * usually fatal; there is no reason for them to be checked.

+ 64 - 20
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}.
  * 
- * <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);

+ 63 - 19
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}.
  * </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);
 

+ 3 - 6
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."));
         }
     }
 

+ 3 - 6
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."));
         }
     }
 

+ 2 - 0
test/.cvsignore

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

+ 23 - 0
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$