From 82c15b18748d7bf9f4bd2cf7951757b88b4d75e0 Mon Sep 17 00:00:00 2001 From: Ray Krueger Date: Mon, 31 Jan 2005 05:16:32 +0000 Subject: [PATCH] The JaasAuthenticationCallbackHandler handle method now takes a callback and the authentication in progress, the setAuthentication method has been removed. The JaasAuthenticationProvider afterPropertiesSet method now makes use of the java.security.auth.login.config System property before trying to use the login.config.url.X properties. --- .../JaasAuthenticationCallbackHandler.java | 16 +-- .../jaas/JaasAuthenticationProvider.java | 118 ++++++++++-------- .../jaas/JaasNameCallbackHandler.java | 16 +-- .../jaas/JaasPasswordCallbackHandler.java | 17 +-- .../jaas/JaasAuthenticationProviderTests.java | 22 +++- .../providers/jaas/TestCallbackHandler.java | 12 +- .../jaas/JaasAuthenticationProviderTests.conf | 3 + 7 files changed, 99 insertions(+), 105 deletions(-) create mode 100644 core/src/test/resources/org/acegisecurity/providers/jaas/JaasAuthenticationProviderTests.conf diff --git a/core/src/main/java/org/acegisecurity/providers/jaas/JaasAuthenticationCallbackHandler.java b/core/src/main/java/org/acegisecurity/providers/jaas/JaasAuthenticationCallbackHandler.java index 5ea77fc60c..754c30200d 100644 --- a/core/src/main/java/org/acegisecurity/providers/jaas/JaasAuthenticationCallbackHandler.java +++ b/core/src/main/java/org/acegisecurity/providers/jaas/JaasAuthenticationCallbackHandler.java @@ -50,29 +50,19 @@ import javax.security.auth.callback.UnsupportedCallbackException; public interface JaasAuthenticationCallbackHandler { //~ Methods ================================================================ - /** - * Called by the JaasAuthenticationProvider before calling the handle - * method for any Callbacks. - * - * @param auth The Authentication object currently being authenticated. - */ - void setAuthentication(Authentication auth); - /** * Handle the Callback. * The handle method will be called for every callback instance sent from * the LoginContext. Meaning that The handle method may be called multiple - * times for a given JaasAuthenticationCallbackHandler, after a single - * call to the {@link - * #setAuthentication(net.sf.acegisecurity.Authentication) - * setAuthentication} method. + * times for a given JaasAuthenticationCallbackHandler. * * @param callback + * @param auth The Authentication object currently being authenticated. * * @throws IOException * @throws UnsupportedCallbackException */ - void handle(Callback callback) + void handle(Callback callback, Authentication auth) throws IOException, UnsupportedCallbackException; } diff --git a/core/src/main/java/org/acegisecurity/providers/jaas/JaasAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/jaas/JaasAuthenticationProvider.java index c3af24c1ca..dbf49f86f7 100644 --- a/core/src/main/java/org/acegisecurity/providers/jaas/JaasAuthenticationProvider.java +++ b/core/src/main/java/org/acegisecurity/providers/jaas/JaasAuthenticationProvider.java @@ -15,6 +15,7 @@ package net.sf.acegisecurity.providers.jaas; +import com.sun.security.auth.login.ConfigFile; import net.sf.acegisecurity.AcegiSecurityException; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.AuthenticationException; @@ -23,43 +24,38 @@ import net.sf.acegisecurity.providers.AuthenticationProvider; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import net.sf.acegisecurity.providers.jaas.event.JaasAuthenticationFailedEvent; import net.sf.acegisecurity.providers.jaas.event.JaasAuthenticationSuccessEvent; - import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; - import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextException; - import org.springframework.core.io.Resource; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.Configuration; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; import java.io.IOException; - import java.security.Principal; import java.security.Security; - import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.Set; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; - /** * An {@link AuthenticationProvider} implementation that retrieves user details * from a JAAS login configuration. - * + * *

* This AuthenticationProvider is capable of validating {@link * net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken} * requests contain the correct username and password. *

- * + * *

* This implementation is backed by a JAAS @@ -69,7 +65,7 @@ import javax.security.auth.login.LoginException; * configuration file containing an index matching the {@link * #setLoginContextName(java.lang.String) loginContextName} property. *

- * + * *

* For example: If this JaasAuthenticationProvider were configured in a Spring * WebApplicationContext the xml to set the loginConfiguration could be as @@ -80,7 +76,7 @@ import javax.security.auth.login.LoginException; * </property> * *

- * + * *

* The loginContextName should coincide with a given index in the loginConfig * specifed. The loginConfig file used in the JUnit tests appears as the @@ -98,7 +94,7 @@ import javax.security.auth.login.LoginException; * </property> * *

- * + * *

* When using JAAS login modules as the authentication source, sometimes the LoginContext @@ -110,7 +106,7 @@ import javax.security.auth.login.LoginException; * CallbackHandler, control is passed to each {@link * JaasAuthenticationCallbackHandler} for each Callback passed. *

- * + * *

* {{@link JaasAuthenticationCallbackHandler}s are passed to the * JaasAuthenticationProvider through the {@link @@ -126,7 +122,7 @@ import javax.security.auth.login.LoginException; * </property> * *

- * + * *

* After calling LoginContext.login(), the JaasAuthenticationProvider will * retrieve the returned Principals from the Subject @@ -138,7 +134,7 @@ import javax.security.auth.login.LoginException; * method. The returned role will be applied to the Authorization object as a * {@link GrantedAuthority}. *

- * + * *

* AuthorityGranters are configured in spring xml as follows... *

@@ -155,7 +151,7 @@ import javax.security.auth.login.LoginException;
  * @version $Id$
  */
 public class JaasAuthenticationProvider implements AuthenticationProvider,
-    InitializingBean, ApplicationContextAware {
+        InitializingBean, ApplicationContextAware {
     //~ Instance fields ========================================================
 
     private ApplicationContext context;
@@ -164,11 +160,12 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
     private String loginContextName = "ACEGI";
     private AuthorityGranter[] authorityGranters;
     private JaasAuthenticationCallbackHandler[] callbackHandlers;
+    private final String SYSPROP = "java.security.auth.login.config";
 
     //~ Methods ================================================================
 
     public void setApplicationContext(ApplicationContext applicationContext)
-        throws BeansException {
+            throws BeansException {
         this.context = applicationContext;
     }
 
@@ -177,7 +174,6 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
      * granted to the Authentication.
      *
      * @param authorityGranters AuthorityGranter array
-     *
      * @see JaasAuthenticationProvider
      */
     public void setAuthorityGranters(AuthorityGranter[] authorityGranters) {
@@ -190,7 +186,6 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
      * were ever set.
      *
      * @return The AuthorityGranter array, or null
-     *
      * @see #setAuthorityGranters(net.sf.acegisecurity.providers.jaas.AuthorityGranter[])
      */
     public AuthorityGranter[] getAuthorityGranters() {
@@ -203,8 +198,7 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
      *
      * @param callbackHandlers Array of JAASAuthenticationCallbackHandlers
      */
-    public void setCallbackHandlers(
-        JaasAuthenticationCallbackHandler[] callbackHandlers) {
+    public void setCallbackHandlers(JaasAuthenticationCallbackHandler[] callbackHandlers) {
         this.callbackHandlers = callbackHandlers;
     }
 
@@ -213,7 +207,6 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
      * none are set.
      *
      * @return the JAASAuthenticationCallbackHandlers.
-     *
      * @see #setCallbackHandlers(net.sf.acegisecurity.providers.jaas.JaasAuthenticationCallbackHandler[])
      */
     public JaasAuthenticationCallbackHandler[] getCallbackHandlers() {
@@ -224,9 +217,8 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
      * Set the JAAS login configuration file.
      *
      * @param loginConfig Spring
-     *        Resource
-     *
+     *                    href="http://www.springframework.org/docs/api/org/springframework/core/io/Resource.html">Spring
+     *                    Resource
      * @see JAAS
      *      Reference
@@ -253,8 +245,7 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
         return loginContextName;
     }
 
-    public void setLoginExceptionResolver(
-        LoginExceptionResolver loginExceptionResolver) {
+    public void setLoginExceptionResolver(LoginExceptionResolver loginExceptionResolver) {
         this.loginExceptionResolver = loginExceptionResolver;
     }
 
@@ -265,22 +256,24 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
     public void afterPropertiesSet() throws Exception {
         if (loginConfig == null) {
             throw new ApplicationContextException("loginConfig must be set on "
-                + getClass());
+                    + getClass());
         }
 
         if ((loginContextName == null) || "".equals(loginContextName)) {
-            throw new ApplicationContextException(
-                "loginContextName must be set on " + getClass());
+            throw new ApplicationContextException("loginContextName must be set on " + getClass());
         }
 
-        int n = 1;
+        String loginConfigStr = loginConfig.getURL().toString();
 
-        while (Security.getProperty("login.config.url." + n) != null) {
-            n++;
+        boolean allowed = "true".equalsIgnoreCase(Security.getProperty("policy.allowSystemProperty"));
+
+        if (allowed) {
+            System.setProperty(SYSPROP, loginConfigStr);
+        } else {
+            setPropertyUsingLoop(loginConfigStr);
         }
 
-        Security.setProperty("login.config.url." + n,
-            loginConfig.getURL().toString());
+        Configuration.setConfiguration(new ConfigFile());
     }
 
     /**
@@ -288,18 +281,16 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
      * and credential
      *
      * @param auth The Authentication object to be authenticated.
-     *
      * @return The authenticated Authentication object, with it's
      *         grantedAuthorities set.
-     *
      * @throws AuthenticationException This implementation does not handle
-     *         'locked' or 'disabled' accounts. This method only throws a
-     *         AuthenticationServiceException, with the message of the
-     *         LoginException that will be thrown, should the
-     *         loginContext.login() method fail.
+     *                                 'locked' or 'disabled' accounts. This method only throws a
+     *                                 AuthenticationServiceException, with the message of the
+     *                                 LoginException that will be thrown, should the
+     *                                 loginContext.login() method fail.
      */
     public Authentication authenticate(Authentication auth)
-        throws AuthenticationException {
+            throws AuthenticationException {
         if (auth instanceof UsernamePasswordAuthenticationToken) {
             UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) auth;
 
@@ -322,7 +313,7 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
                 Set principals = lc.getSubject().getPrincipals();
 
                 for (Iterator iterator = principals.iterator();
-                    iterator.hasNext();) {
+                     iterator.hasNext();) {
                     Principal principal = (Principal) iterator.next();
 
                     for (int i = 0; i < authorityGranters.length; i++) {
@@ -338,8 +329,7 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
                 }
 
                 //Convert the authorities set back to an array and apply it to the token.
-                token.setAuthorities((GrantedAuthority[]) authorities.toArray(
-                        new GrantedAuthority[authorities.size()]));
+                token.setAuthorities((GrantedAuthority[]) authorities.toArray(new GrantedAuthority[authorities.size()]));
 
                 //Publish the success event
                 context.publishEvent(new JaasAuthenticationSuccessEvent(token));
@@ -348,7 +338,7 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
                 return token;
             } catch (LoginException loginException) {
                 AcegiSecurityException ase = loginExceptionResolver
-                    .resolveException(loginException);
+                        .resolveException(loginException);
 
                 context.publishEvent(new JaasAuthenticationFailedEvent(auth, ase));
                 throw ase;
@@ -362,6 +352,28 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
         return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
     }
 
+    private void setPropertyUsingLoop(String loginConfigStr) {
+        boolean alreadySet = false;
+
+        int n = 1;
+        String prefix = "login.config.url.";
+        String existing = null;
+
+        while ((existing = Security.getProperty(prefix + n)) != null) {
+            alreadySet = existing.equals(loginConfigStr);
+
+            if (alreadySet) {
+                break;
+            }
+
+            n++;
+        }
+
+        if (!alreadySet) {
+            Security.setProperty(prefix + n, loginConfigStr);
+        }
+    }
+
     //~ Inner Classes ==========================================================
 
     /**
@@ -375,16 +387,14 @@ public class JaasAuthenticationProvider implements AuthenticationProvider,
         }
 
         public void handle(Callback[] callbacks)
-            throws IOException, UnsupportedCallbackException {
+                throws IOException, UnsupportedCallbackException {
             for (int i = 0; i < callbackHandlers.length; i++) {
                 JaasAuthenticationCallbackHandler handler = callbackHandlers[i];
 
-                handler.setAuthentication(authentication);
-
                 for (int j = 0; j < callbacks.length; j++) {
                     Callback callback = callbacks[j];
 
-                    handler.handle(callback);
+                    handler.handle(callback, authentication);
                 }
             }
         }
diff --git a/core/src/main/java/org/acegisecurity/providers/jaas/JaasNameCallbackHandler.java b/core/src/main/java/org/acegisecurity/providers/jaas/JaasNameCallbackHandler.java
index d874494055..46ca6df94c 100644
--- a/core/src/main/java/org/acegisecurity/providers/jaas/JaasNameCallbackHandler.java
+++ b/core/src/main/java/org/acegisecurity/providers/jaas/JaasNameCallbackHandler.java
@@ -40,30 +40,20 @@ import javax.security.auth.callback.UnsupportedCallbackException;
  */
 public class JaasNameCallbackHandler
     implements JaasAuthenticationCallbackHandler {
-    //~ Instance fields ========================================================
-
-    private Authentication authentication;
-
     //~ Methods ================================================================
 
-    public void setAuthentication(Authentication authentication) {
-        this.authentication = authentication;
-    }
-
     /**
      * If the callback passed to the 'handle' method is an instance of
      * NameCallback, the JaasNameCallbackHandler will call,
-     * callback.setName(authentication.getPrincipal().toString()). Where
-     * 'authentication' is the {@link Authentication} object used in the
-     * {@link #setAuthentication(net.sf.acegisecurity.Authentication)
-     * setAuthentication} method.
+     * callback.setName(authentication.getPrincipal().toString()).
      *
      * @param callback
+     * @param authentication
      *
      * @throws IOException
      * @throws UnsupportedCallbackException
      */
-    public void handle(Callback callback)
+    public void handle(Callback callback, Authentication authentication)
         throws IOException, UnsupportedCallbackException {
         if (callback instanceof NameCallback) {
             NameCallback ncb = (NameCallback) callback;
diff --git a/core/src/main/java/org/acegisecurity/providers/jaas/JaasPasswordCallbackHandler.java b/core/src/main/java/org/acegisecurity/providers/jaas/JaasPasswordCallbackHandler.java
index 82813d8346..b0e4346ddd 100644
--- a/core/src/main/java/org/acegisecurity/providers/jaas/JaasPasswordCallbackHandler.java
+++ b/core/src/main/java/org/acegisecurity/providers/jaas/JaasPasswordCallbackHandler.java
@@ -40,31 +40,20 @@ import javax.security.auth.callback.UnsupportedCallbackException;
  */
 public class JaasPasswordCallbackHandler
     implements JaasAuthenticationCallbackHandler {
-    //~ Instance fields ========================================================
-
-    private Authentication auth;
-
     //~ Methods ================================================================
 
-    public void setAuthentication(Authentication auth) {
-        this.auth = auth;
-    }
-
     /**
      * If the callback passed to the 'handle' method is an instance of
      * PasswordCallback, the JaasPasswordCallbackHandler will call,
-     * callback.setPassword(authentication.getCredentials().toString()). Where
-     * 'authentication' is the {@link Authentication} object used in the
-     * {@link
-     * JaasAuthenticationCallbackHandler#setAuthentication(net.sf.acegisecurity.Authentication)
-     * setAuthentication} method.
+     * callback.setPassword(authentication.getCredentials().toString()).
      *
      * @param callback
+     * @param auth
      *
      * @throws IOException
      * @throws UnsupportedCallbackException
      */
-    public void handle(Callback callback)
+    public void handle(Callback callback, Authentication auth)
         throws IOException, UnsupportedCallbackException {
         if (callback instanceof PasswordCallback) {
             PasswordCallback pc = (PasswordCallback) callback;
diff --git a/core/src/test/java/org/acegisecurity/providers/jaas/JaasAuthenticationProviderTests.java b/core/src/test/java/org/acegisecurity/providers/jaas/JaasAuthenticationProviderTests.java
index 21f6e01ba6..063cef8b8d 100644
--- a/core/src/test/java/org/acegisecurity/providers/jaas/JaasAuthenticationProviderTests.java
+++ b/core/src/test/java/org/acegisecurity/providers/jaas/JaasAuthenticationProviderTests.java
@@ -17,7 +17,12 @@ package net.sf.acegisecurity.providers.jaas;
 
 import junit.framework.TestCase;
 
-import net.sf.acegisecurity.*;
+import net.sf.acegisecurity.AcegiSecurityException;
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.AuthenticationException;
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.LockedException;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 
@@ -25,6 +30,10 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextException;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 
+import java.net.URL;
+
+import java.security.Security;
+
 import java.util.Arrays;
 import java.util.List;
 
@@ -72,6 +81,17 @@ public class JaasAuthenticationProviderTests extends TestCase {
         assertNull("Success event was fired", eventCheck.successEvent);
     }
 
+    public void testConfigurationLoop() throws Exception {
+        String resName = "/" + getClass().getName().replace('.', '/') + ".conf";
+        URL url = getClass().getResource(resName);
+
+        Security.setProperty("policy.allowSystemProperty", "false");
+        Security.setProperty("login.config.url.1", url.toString());
+
+        setUp();
+        testFull();
+    }
+
     public void testDetectsMissingLoginConfig() throws Exception {
         JaasAuthenticationProvider myJaasProvider = new JaasAuthenticationProvider();
         myJaasProvider.setApplicationContext(context);
diff --git a/core/src/test/java/org/acegisecurity/providers/jaas/TestCallbackHandler.java b/core/src/test/java/org/acegisecurity/providers/jaas/TestCallbackHandler.java
index f694edf159..5b67ca6d65 100644
--- a/core/src/test/java/org/acegisecurity/providers/jaas/TestCallbackHandler.java
+++ b/core/src/test/java/org/acegisecurity/providers/jaas/TestCallbackHandler.java
@@ -25,23 +25,15 @@ import javax.security.auth.callback.UnsupportedCallbackException;
 
 
 /**
- * DOCUMENT ME!
+ * TestCallbackHandler
  *
  * @author Ray Krueger
  * @version $Id$
  */
 public class TestCallbackHandler implements JaasAuthenticationCallbackHandler {
-    //~ Instance fields ========================================================
-
-    Authentication auth;
-
     //~ Methods ================================================================
 
-    public void setAuthentication(Authentication auth) {
-        this.auth = auth;
-    }
-
-    public void handle(Callback callback)
+    public void handle(Callback callback, Authentication auth)
         throws IOException, UnsupportedCallbackException {
         if (callback instanceof TextInputCallback) {
             TextInputCallback tic = (TextInputCallback) callback;
diff --git a/core/src/test/resources/org/acegisecurity/providers/jaas/JaasAuthenticationProviderTests.conf b/core/src/test/resources/org/acegisecurity/providers/jaas/JaasAuthenticationProviderTests.conf
new file mode 100644
index 0000000000..272ca7c1af
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/providers/jaas/JaasAuthenticationProviderTests.conf
@@ -0,0 +1,3 @@
+JAASTest2 {
+    net.sf.acegisecurity.providers.jaas.TestLoginModule required;
+};
\ No newline at end of file