Committing ConcurrentSessionController feature and tests. Documentation is needed.

This commit is contained in:
Ray Krueger 2005-02-26 21:48:07 +00:00
parent edd3fcc72c
commit 44397bb05d
9 changed files with 704 additions and 9 deletions

View File

@ -0,0 +1,33 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.AuthenticationException;
/**
* Thrown by the ConcurrentSessionController when the number of sessions
* allowed is attempting to be exceeded.
*
* @author Ray Krueger
*/
public class ConcurrentLoginException extends AuthenticationException {
//~ Constructors ===========================================================
public ConcurrentLoginException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,36 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
/**
* See: {@link ConcurrentSessionControllerImpl}
*
* @author Ray Krueger
* @see ConcurrentSessionControllerImpl
*/
public interface ConcurrentSessionController {
//~ Methods ================================================================
void afterAuthentication(Authentication initialAuth, Authentication result)
throws AuthenticationException;
void beforeAuthentication(Authentication initialAuth)
throws AuthenticationException;
}

View File

@ -0,0 +1,290 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationTrustResolver;
import net.sf.acegisecurity.AuthenticationTrustResolverImpl;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.ui.WebAuthenticationDetails;
import net.sf.acegisecurity.ui.session.HttpSessionDestroyedEvent;
import org.springframework.context.ApplicationEvent;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpSession;
/**
* Used by the {@link ProviderManager} to track Authentications and their
* respective sessions. A given user is allowed {@link #setMaxSessions(int)}
* sessions. If they attempt to exceed that ammount a {@link
* ConcurrentLoginException} will be thrown. The
* ConcurrentSessionControllerImpl class will listen for {@link
* HttpSessionDestroyedEvent}s in the ApplicationContext to remove a session
* from the internal tracking. <b>This class will not function properly
* without a {@link net.sf.acegisecurity.ui.session.HttpSessionEventPublisher}
* configured in web.xml.</b>
*
* @author Ray Krueger
* @author Ben Alex
*/
public class ConcurrentSessionControllerImpl
implements ConcurrentSessionController {
//~ Instance fields ========================================================
protected Map principalsToSessions = new HashMap();
protected Map sessionsToPrincipals = new HashMap();
protected Set sessionSet = new HashSet();
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private int maxSessions = 1;
//~ Methods ================================================================
/**
* Set the maximum number of sessions a user is allowed to have, defaults
* to 1. Setting this to anything less than 1 will allow unlimited
* sessions
*
* @param maxSessions
*/
public void setMaxSessions(int maxSessions) {
this.maxSessions = maxSessions;
}
/**
* The maximum sessions per user.
*
* @return int
*/
public int getMaxSessions() {
return maxSessions;
}
/**
* The trustResolver to use for determining Anonymous users and ignoring
* them. Defaults to {@link AuthenticationTrustResolverImpl}
*
* @param trustResolver
*/
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
this.trustResolver = trustResolver;
}
/**
* Get the configured AuthenticationTrustResolver
*
* @return The configured AuthenticationTrustResolver or {@link
* AuthenticationTrustResolverImpl} by default.
*/
public AuthenticationTrustResolver getTrustResolver() {
return trustResolver;
}
/**
* Called by the {@link ProviderManager} after receiving a response from a
* configured AuthenticationProvider.
*
* @param request Used to retieve the {@link WebAuthenticationDetails}
* @param response Used to store the sessionId for the current Principal
*
* @see #determineSessionPrincipal(net.sf.acegisecurity.Authentication)
*/
public void afterAuthentication(Authentication request,
Authentication response) {
enforceConcurrentLogins(response);
if (request.getDetails() instanceof WebAuthenticationDetails) {
String sessionId = ((WebAuthenticationDetails) request.getDetails())
.getSessionId();
addSession(determineSessionPrincipal(response), sessionId);
}
}
/**
* Called by the {@link ProviderManager} before iterating the configured
* {@link AuthenticationProvider}s
*
* @param request The Authentication in question
*
* @throws ConcurrentLoginException if the user has already met the {@link
* #setMaxSessions(int)}
*/
public void beforeAuthentication(Authentication request)
throws ConcurrentLoginException {
enforceConcurrentLogins(request);
}
/**
* Checks for {@link HttpSessionDestroyedEvent}s and calls {@link
* #removeSession(String)} for the destoyed HttpSessions id.
*
* @param event
*/
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof HttpSessionDestroyedEvent) {
String sessionId = ((HttpSession) event.getSource()).getId();
removeSession(sessionId);
}
}
/**
* Compares the sessionIds stored for the given principal to determine if
* the given sessionId is new or existing.
*
* @param principal The principal in question
* @param sessionId The new or existing sessionId
*
* @return true if it's the same as a session already in use, false if it
* is a new session
*/
protected boolean isActiveSession(Object principal, String sessionId) {
Set sessions = (Set) principalsToSessions.get(principal);
if (sessions == null) {
return false;
}
return sessions.contains(sessionId);
}
/**
* Updates internal maps with the sessionId for the given principal. Can be
* overridden by subclasses to provide a specialized means of principal
* -&gt; session tracking.
*
* @param principal
* @param sessionId
*/
protected void addSession(Object principal, String sessionId) {
Set sessions = (Set) principalsToSessions.get(principal);
if (sessions == null) {
sessions = new HashSet();
principalsToSessions.put(principal, sessions);
}
sessions.add(sessionId);
sessionsToPrincipals.put(sessionId, principal);
}
/**
* Counts the number of sessions in use by the given principal
*
* @param principal The principal object
*
* @return 0 if there are no sessions, &gt; if there are any
*/
protected int countSessions(Object principal) {
Set set = (Set) principalsToSessions.get(principal);
if (set == null) {
return 0;
}
return set.size();
}
/**
* Checks to see if the Authentication principal is of type UserDetails. If
* it is then the {@link net.sf.acegisecurity.UserDetails#getUsername()}
* is returned. Otherwise Authentication.getPrincipal().toString() is
* returned. Subclasses can override this method to provide a more
* specific implementation.
*
* @param auth The Authentication in question
*
* @return The principal to be used as the key against sessions
*/
protected Object determineSessionPrincipal(Authentication auth) {
if (auth.getPrincipal() instanceof UserDetails) {
return ((UserDetails) auth.getPrincipal()).getUsername();
} else {
return auth.getPrincipal().toString();
}
}
/**
* Called by both the beforeAuthentication and afterAuthentication methods.
* Anonymous requests as determined by the configured {@link
* AuthenticationTrustResolver} are ignored. If the details are
* WebAuthenticationDetails, get the sessionId and and the principal off
* of the authentication using the {@link
* #determineSessionPrincipal(net.sf.acegisecurity.Authentication)}
* method. Uses the sessionId and principal to determine if the session
* is new, and if the user is already at the maxSessions value. Subclasses
* may override for more specific functionality
*
* @param request Authentication being evaluated
*
* @throws ConcurrentLoginException If the session is new, and the user is
* already at maxSessions
*/
protected void enforceConcurrentLogins(Authentication request)
throws ConcurrentLoginException {
//If the max is less than 1, sessions are unlimited
if (maxSessions < 1) {
return;
}
//If it is an anonymous user, ignore them
if (trustResolver.isAnonymous(request)) {
return;
}
if (request.getDetails() instanceof WebAuthenticationDetails) {
String sessionId = ((WebAuthenticationDetails) request.getDetails())
.getSessionId();
Object principal = determineSessionPrincipal(request);
if (!isActiveSession(principal, sessionId)) {
if (maxSessions == countSessions(principal)) {
//The user is AT their max, toss them out
throw new ConcurrentLoginException(principal
+ " has reached the maximum concurrent logins");
}
}
}
}
/**
* Remove the given sessionId from storage. Used by {@link
* #onApplicationEvent(org.springframework.context.ApplicationEvent)} for
* HttpSessionDestroyedEvent
*
* @param sessionId
*/
protected void removeSession(String sessionId) {
// find out which principal is associated with this sessionId
Object associatedPrincipal = sessionsToPrincipals.get(sessionId);
if (associatedPrincipal != null) {
Set sessions = (Set) principalsToSessions.get(associatedPrincipal);
sessions.remove(sessionId);
if (sessions.isEmpty()) {
principalsToSessions.remove(associatedPrincipal);
}
sessionsToPrincipals.remove(sessionId);
}
}
}

View File

@ -0,0 +1,41 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
/**
* Do nothing implementation of ConcurrentSessionController. This is the {@link ProviderManager} default
*
* @author Ray Krueger
* @see ConcurrentSessionControllerImpl
*/
public class NullConcurrentSessionController
implements ConcurrentSessionController {
//~ Methods ================================================================
public void afterAuthentication(Authentication initialAuth,
Authentication result) throws AuthenticationException {
//Do nothing
}
public void beforeAuthentication(Authentication initialAuth)
throws AuthenticationException {
//Do nothing
}
}

View File

@ -1,4 +1,4 @@
/* Copyright 2004 Acegi Technology Pty Limited /* Copyright 2004, 2005 Acegi Technology Pty Limited
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -30,11 +30,16 @@ import java.util.List;
/** /**
* Iterates an {@link Authentication} request through a list of {@link * Iterates an {@link Authentication} request through a list of {@link
* AuthenticationProvider}s. * AuthenticationProvider}s. Can optionally be configured with a {@link
* ConcurrentSessionController} to limit the number of sessions a user can
* have.
* *
* @author Ben Alex * @author Ben Alex
* @author Wesley Hall * @author Wesley Hall
* @author Ray Krueger
* @version $Id$ * @version $Id$
*
* @see ConcurrentSessionController
*/ */
public class ProviderManager extends AbstractAuthenticationManager public class ProviderManager extends AbstractAuthenticationManager
implements InitializingBean { implements InitializingBean {
@ -44,6 +49,7 @@ public class ProviderManager extends AbstractAuthenticationManager
//~ Instance fields ======================================================== //~ Instance fields ========================================================
private ConcurrentSessionController sessionController = new NullConcurrentSessionController();
private List providers; private List providers;
//~ Methods ================================================================ //~ Methods ================================================================
@ -82,6 +88,29 @@ public class ProviderManager extends AbstractAuthenticationManager
return this.providers; return this.providers;
} }
/**
* Set the {@link ConcurrentSessionController} to be used for limiting
* user's sessions. The {@link NullConcurrentSessionController} is used
* by default
*
* @param sessionController {@link ConcurrentSessionController}
*/
public void setSessionController(
ConcurrentSessionController sessionController) {
this.sessionController = sessionController;
}
/**
* The configured {@link ConcurrentSessionController} is returned or the
* {@link NullConcurrentSessionController} if a specific one has not been
* set.
*
* @return{@link ConcurrentSessionController} instance
*/
public ConcurrentSessionController getSessionController() {
return sessionController;
}
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
checkIfValidList(this.providers); checkIfValidList(this.providers);
} }
@ -117,6 +146,8 @@ public class ProviderManager extends AbstractAuthenticationManager
Class toTest = authentication.getClass(); Class toTest = authentication.getClass();
sessionController.beforeAuthentication(authentication);
while (iter.hasNext()) { while (iter.hasNext()) {
AuthenticationProvider provider = (AuthenticationProvider) iter AuthenticationProvider provider = (AuthenticationProvider) iter
.next(); .next();
@ -128,6 +159,8 @@ public class ProviderManager extends AbstractAuthenticationManager
Authentication result = provider.authenticate(authentication); Authentication result = provider.authenticate(authentication);
if (result != null) { if (result != null) {
sessionController.afterAuthentication(authentication, result);
return result; return result;
} }
} }

View File

@ -0,0 +1,244 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers;
import junit.framework.TestCase;
import net.sf.acegisecurity.*;
import net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
import net.sf.acegisecurity.providers.dao.User;
import net.sf.acegisecurity.ui.WebAuthenticationDetails;
import net.sf.acegisecurity.ui.session.HttpSessionCreatedEvent;
import net.sf.acegisecurity.ui.session.HttpSessionDestroyedEvent;
import java.security.Principal;
/**
* Tests for {@link ConcurrentSessionControllerImpl}
*
* @author Ray Krueger
*/
public class ConcurrentSessionControllerImplTests extends TestCase {
//~ Instance fields ========================================================
ConcurrentSessionControllerImpl target = new ConcurrentSessionControllerImpl();
//~ Methods ================================================================
public void testBumpCoverage() throws Exception {
target.onApplicationEvent(new HttpSessionCreatedEvent(new MockHttpSession()));
}
public void testEnforcementKnownGood() throws Exception {
Authentication auth = createAuthentication("user", "password", "session");
target.beforeAuthentication(auth);
target.afterAuthentication(auth, auth);
}
public void testEnforcementMultipleSessions() throws Exception {
target.setMaxSessions(5);
Authentication auth = null;
for (int i = 0; i < 5; i++) {
auth = createAuthentication("user", "password", String.valueOf(i));
target.beforeAuthentication(auth);
target.afterAuthentication(auth, auth);
}
try {
auth = createAuthentication("user", "password", "lastsession");
target.beforeAuthentication(auth);
fail("Only allowed 5 sessions, this should have thrown a ConcurrentLoginException");
} catch (ConcurrentLoginException e) {
assertTrue(e.getMessage().startsWith(auth.getPrincipal().toString()));
}
}
public void testEnforcementSingleSession() throws Exception {
target.setMaxSessions(1);
Authentication auth = createAuthentication("user", "password",
"session1");
target.beforeAuthentication(auth);
target.afterAuthentication(auth, auth);
try {
target.beforeAuthentication(createAuthentication("user",
"password", "session2"));
fail("Only allowed 1 session, this should have thrown a ConcurrentLoginException");
} catch (ConcurrentLoginException e) {
}
}
public void testEnforcementUnlimitedSameSession() throws Exception {
target.setMaxSessions(1);
for (int i = 0; i < 100; i++) {
Authentication auth = createAuthentication("user", "password",
"samesession");
target.beforeAuthentication(auth);
target.afterAuthentication(auth, auth);
}
}
public void testEnforcementUnlimitedSessions() throws Exception {
target.setMaxSessions(0);
for (int i = 0; i < 100; i++) {
Authentication auth = createAuthentication("user", "password",
String.valueOf(i));
target.beforeAuthentication(auth);
target.afterAuthentication(auth, auth);
}
}
public void testEventHandler() throws Exception {
target.setMaxSessions(1);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("user",
"password");
MockHttpSession session = new MockHttpSession();
MockHttpServletRequest request = new MockHttpServletRequest(auth,
session);
auth.setDetails(new WebAuthenticationDetails(request));
target.beforeAuthentication(auth);
target.afterAuthentication(auth, auth);
target.onApplicationEvent(new HttpSessionDestroyedEvent(session));
Authentication different = createAuthentication("user", "password",
"differentsession");
target.beforeAuthentication(different);
target.afterAuthentication(different, different);
}
public void testNonWebDetails() throws Exception {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("asdf",
"asdf");
auth.setDetails("Hi there");
target.beforeAuthentication(auth);
target.afterAuthentication(auth, auth);
}
public void testPrincipals() throws Exception {
target.setMaxSessions(1);
final UserDetails user = new User("user", "password", true, true, true,
new GrantedAuthority[0]);
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user,
"password", user.getAuthorities());
auth.setDetails(createWebDetails(auth, "session1"));
target.beforeAuthentication(auth);
target.afterAuthentication(auth, auth);
try {
UsernamePasswordAuthenticationToken otherAuth = new UsernamePasswordAuthenticationToken(new Principal() {
public String getName() {
return "user";
}
public String toString() {
return getName();
}
}, "password");
otherAuth.setDetails(createWebDetails(otherAuth, "session2"));
target.beforeAuthentication(otherAuth);
fail("Same principal, different principal type, different session should have thrown ConcurrentLoginException");
} catch (ConcurrentLoginException e) {
}
}
public void testSetMax() throws Exception {
target.setMaxSessions(1);
assertEquals(1, target.getMaxSessions());
target.setMaxSessions(2);
assertEquals(2, target.getMaxSessions());
}
public void testSetTrustManager() throws Exception {
assertNotNull("There is supposed to be a default AuthenticationTrustResolver",
target.getTrustResolver());
AuthenticationTrustResolverImpl impl = new AuthenticationTrustResolverImpl();
target.setTrustResolver(impl);
assertEquals(impl, target.getTrustResolver());
}
public void testUtilityMethods() throws Exception {
Object key = new Object();
target.addSession(key, "1");
target.addSession(key, "2");
target.addSession(key, "3");
target.removeSession("2");
assertFalse(target.isActiveSession(key, "2"));
assertTrue(target.isActiveSession(key, "1"));
assertTrue(target.isActiveSession(key, "3"));
assertNull(target.sessionsToPrincipals.get("2"));
assertEquals(2, target.countSessions(key));
target.addSession(key, "2");
assertEquals(3, target.countSessions(key));
target.addSession(key, "2");
target.addSession(key, "2");
assertEquals(3, target.countSessions(key));
assertTrue(target.isActiveSession(key, "1"));
assertTrue(target.isActiveSession(key, "2"));
assertTrue(target.isActiveSession(key, "3"));
assertFalse(target.isActiveSession(key, "nope"));
assertFalse(target.isActiveSession(new Object(), "1"));
assertFalse(target.isActiveSession(new Object(), "1"));
target.removeSession("nothing to see here");
}
private Authentication createAuthentication(String user, String password,
String sessionId) {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user,
password);
auth.setDetails(createWebDetails(auth, sessionId));
return auth;
}
private WebAuthenticationDetails createWebDetails(Authentication auth,
String sessionId) {
MockHttpSession session = new MockHttpSession(sessionId);
MockHttpServletRequest request = new MockHttpServletRequest(auth,
session);
return new WebAuthenticationDetails(request);
}
public void testAnonymous() throws Exception {
AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken("blah", "anon", new GrantedAuthority[]{new GrantedAuthorityImpl("ROLE_ANON")});
target.beforeAuthentication(auth);
target.afterAuthentication(auth, auth);
}
}

View File

@ -1,4 +1,4 @@
/* Copyright 2004 Acegi Technology Pty Limited /* Copyright 2004, 2005 Acegi Technology Pty Limited
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,11 +17,7 @@ package net.sf.acegisecurity.providers;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.*;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationServiceException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import java.util.List; import java.util.List;
import java.util.Vector; import java.util.Vector;
@ -110,6 +106,19 @@ public class ProviderManagerTests extends TestCase {
assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority()); assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
} }
public void testConcurrentSessionControllerConfiguration()
throws Exception {
ProviderManager target = new ProviderManager();
//The NullConcurrentSessionController should be the default
assertNotNull(target.getSessionController());
assertTrue(target.getSessionController() instanceof NullConcurrentSessionController);
ConcurrentSessionControllerImpl impl = new ConcurrentSessionControllerImpl();
target.setSessionController(impl);
assertEquals(impl, target.getSessionController());
}
public void testStartupFailsIfProviderListDoesNotContainingProviders() public void testStartupFailsIfProviderListDoesNotContainingProviders()
throws Exception { throws Exception {
List providers = new Vector(); List providers = new Vector();

View File

@ -26,7 +26,11 @@ applications:
SecureContext (and its implementation). These classes were moved as part of refactorings aimed at SecureContext (and its implementation). These classes were moved as part of refactorings aimed at
improving the simplicity of the project's design.<br><br></li> improving the simplicity of the project's design.<br><br></li>
<li>The JaasAuthenticationCallbackHandler interface has had it's setAuthentication method removed. The handle method now takes both the Callback and Authentication objects as arguments.<br><br></li> <li>If you wish to use the new ConcurrentSessionController you must declare the HttpSessionEventPublisher context listener in your
web.xml<br><br></li>
<li>The JaasAuthenticationCallbackHandler interface has had it's setAuthentication method removed.
The handle method now takes both the Callback and Authentication objects as arguments.<br><br></li>
<li>Added AuthenticationException to the AutenticationEntryPoint.commence method signature.<br><br></li> <li>Added AuthenticationException to the AutenticationEntryPoint.commence method signature.<br><br></li>

View File

@ -58,6 +58,11 @@
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener> </listener>
<!--
The HttpSessionEventPublisher will publish
HttpSessionCreatedEvent and HttpSessionDestroyedEvent
to the WebApplicationContext
-->
<listener> <listener>
<listener-class>net.sf.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class> <listener-class>net.sf.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
</listener> </listener>