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