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.
This commit is contained in:
parent
358056bf4d
commit
82c15b1874
|
@ -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 <a
|
||||
* href="http://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/Callback.html">Callback</a>.
|
||||
* 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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This <code>AuthenticationProvider</code> is capable of validating {@link
|
||||
* net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken}
|
||||
* requests contain the correct username and password.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This implementation is backed by a <a
|
||||
* href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.html">JAAS</a>
|
||||
|
@ -69,7 +65,7 @@ import javax.security.auth.login.LoginException;
|
|||
* configuration file containing an index matching the {@link
|
||||
* #setLoginContextName(java.lang.String) loginContextName} property.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* 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>
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* 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>
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* When using JAAS login modules as the authentication source, sometimes the <a
|
||||
* href="http://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/login/LoginContext.html">LoginContext</a>
|
||||
|
@ -110,7 +106,7 @@ import javax.security.auth.login.LoginException;
|
|||
* CallbackHandler, control is passed to each {@link
|
||||
* JaasAuthenticationCallbackHandler} for each Callback passed.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* {{@link JaasAuthenticationCallbackHandler}s are passed to the
|
||||
* JaasAuthenticationProvider through the {@link
|
||||
|
@ -126,7 +122,7 @@ import javax.security.auth.login.LoginException;
|
|||
* </property>
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* 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}.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* AuthorityGranters are configured in spring xml as follows...
|
||||
* <pre>
|
||||
|
@ -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 <a
|
||||
* href="http://www.springframework.org/docs/api/org/springframework/core/io/Resource.html">Spring
|
||||
* Resource</a>
|
||||
*
|
||||
* href="http://www.springframework.org/docs/api/org/springframework/core/io/Resource.html">Spring
|
||||
* Resource</a>
|
||||
* @see <a
|
||||
* href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.html">JAAS
|
||||
* Reference</a>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
JAASTest2 {
|
||||
net.sf.acegisecurity.providers.jaas.TestLoginModule required;
|
||||
};
|
Loading…
Reference in New Issue