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