mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-06 18:52:13 +00:00
SEC-243: SessionRegistry.getAllSessions() now accepts an "includeExpiredSessions" argument.
This commit is contained in:
parent
d8a56d4e60
commit
0648c65b0b
@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
/* Copyright 2004, 2005, 2006 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.
|
||||||
@ -18,30 +18,35 @@ package org.acegisecurity.concurrent;
|
|||||||
import org.acegisecurity.AcegiMessageSource;
|
import org.acegisecurity.AcegiMessageSource;
|
||||||
import org.acegisecurity.Authentication;
|
import org.acegisecurity.Authentication;
|
||||||
import org.acegisecurity.AuthenticationException;
|
import org.acegisecurity.AuthenticationException;
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.context.MessageSourceAware;
|
import org.springframework.context.MessageSourceAware;
|
||||||
import org.springframework.context.support.MessageSourceAccessor;
|
import org.springframework.context.support.MessageSourceAccessor;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base implementation of {@link ConcurrentSessionControllerImpl} which
|
* Base implementation of {@link ConcurrentSessionControllerImpl} which
|
||||||
* prohibits simultaneous logins.
|
* prohibits simultaneous logins.
|
||||||
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* By default uses {@link SessionRegistryImpl},
|
* By default uses {@link SessionRegistryImpl}, although any
|
||||||
* although any <code>SessionRegistry</code> may be used.
|
* <code>SessionRegistry</code> may be used.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public class ConcurrentSessionControllerImpl implements ConcurrentSessionController,
|
public class ConcurrentSessionControllerImpl
|
||||||
InitializingBean, MessageSourceAware {
|
implements ConcurrentSessionController, InitializingBean,
|
||||||
|
MessageSourceAware {
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
|
protected MessageSourceAccessor messages = AcegiMessageSource
|
||||||
|
.getAccessor();
|
||||||
private SessionRegistry sessionRegistry = new SessionRegistryImpl();
|
private SessionRegistry sessionRegistry = new SessionRegistryImpl();
|
||||||
private boolean exceptionIfMaximumExceeded = false;
|
private boolean exceptionIfMaximumExceeded = false;
|
||||||
private int maximumSessions = 1;
|
private int maximumSessions = 1;
|
||||||
@ -51,7 +56,7 @@ public class ConcurrentSessionControllerImpl implements ConcurrentSessionControl
|
|||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
Assert.notNull(sessionRegistry, "SessionRegistry required");
|
Assert.notNull(sessionRegistry, "SessionRegistry required");
|
||||||
Assert.isTrue(maximumSessions != 0,
|
Assert.isTrue(maximumSessions != 0,
|
||||||
"MaximumLogins must be either -1 to allow unlimited logins, or a positive integer to specify a maximum");
|
"MaximumLogins must be either -1 to allow unlimited logins, or a positive integer to specify a maximum");
|
||||||
Assert.notNull(this.messages, "A message source must be set");
|
Assert.notNull(this.messages, "A message source must be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,21 +64,22 @@ public class ConcurrentSessionControllerImpl implements ConcurrentSessionControl
|
|||||||
* Allows subclasses to customise behaviour when too many sessions are
|
* Allows subclasses to customise behaviour when too many sessions are
|
||||||
* detected.
|
* detected.
|
||||||
*
|
*
|
||||||
* @param sessionId the session ID of the present request
|
* @param sessionId the session ID of the present request
|
||||||
* @param sessions either <code>null</code> or all unexpired sessions
|
* @param sessions either <code>null</code> or all unexpired sessions
|
||||||
* associated with the principal
|
* associated with the principal
|
||||||
* @param allowableSessions DOCUMENT ME!
|
* @param allowableSessions DOCUMENT ME!
|
||||||
* @param registry an instance of the <code>SessionRegistry</code> for
|
* @param registry an instance of the <code>SessionRegistry</code> for
|
||||||
* subclass use
|
* subclass use
|
||||||
|
*
|
||||||
* @throws ConcurrentLoginException DOCUMENT ME!
|
* @throws ConcurrentLoginException DOCUMENT ME!
|
||||||
*/
|
*/
|
||||||
protected void allowableSessionsExceeded(String sessionId,
|
protected void allowableSessionsExceeded(String sessionId,
|
||||||
SessionInformation[] sessions, int allowableSessions,
|
SessionInformation[] sessions, int allowableSessions,
|
||||||
SessionRegistry registry) {
|
SessionRegistry registry) {
|
||||||
if (exceptionIfMaximumExceeded || (sessions == null)) {
|
if (exceptionIfMaximumExceeded || (sessions == null)) {
|
||||||
throw new ConcurrentLoginException(messages.getMessage(
|
throw new ConcurrentLoginException(messages.getMessage(
|
||||||
"ConcurrentSessionControllerImpl.exceededAllowed",
|
"ConcurrentSessionControllerImpl.exceededAllowed",
|
||||||
new Object[]{new Integer(allowableSessions)},
|
new Object[] {new Integer(allowableSessions)},
|
||||||
"Maximum sessions of {0} for this principal exceeded"));
|
"Maximum sessions of {0} for this principal exceeded"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +88,8 @@ public class ConcurrentSessionControllerImpl implements ConcurrentSessionControl
|
|||||||
|
|
||||||
for (int i = 0; i < sessions.length; i++) {
|
for (int i = 0; i < sessions.length; i++) {
|
||||||
if ((leastRecentlyUsed == null)
|
if ((leastRecentlyUsed == null)
|
||||||
|| sessions[i].getLastRequest()
|
|| sessions[i].getLastRequest()
|
||||||
.before(leastRecentlyUsed.getLastRequest())) {
|
.before(leastRecentlyUsed.getLastRequest())) {
|
||||||
leastRecentlyUsed = sessions[i];
|
leastRecentlyUsed = sessions[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,16 +98,17 @@ public class ConcurrentSessionControllerImpl implements ConcurrentSessionControl
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void checkAuthenticationAllowed(Authentication request)
|
public void checkAuthenticationAllowed(Authentication request)
|
||||||
throws AuthenticationException {
|
throws AuthenticationException {
|
||||||
Assert.notNull(request,
|
Assert.notNull(request,
|
||||||
"Authentication request cannot be null (violation of interface contract)");
|
"Authentication request cannot be null (violation of interface contract)");
|
||||||
|
|
||||||
Object principal = SessionRegistryUtils
|
Object principal = SessionRegistryUtils
|
||||||
.obtainPrincipalFromAuthentication(request);
|
.obtainPrincipalFromAuthentication(request);
|
||||||
String sessionId = SessionRegistryUtils
|
String sessionId = SessionRegistryUtils
|
||||||
.obtainSessionIdFromAuthentication(request);
|
.obtainSessionIdFromAuthentication(request);
|
||||||
|
|
||||||
SessionInformation[] sessions = sessionRegistry.getAllSessions(principal);
|
SessionInformation[] sessions = sessionRegistry.getAllSessions(principal,
|
||||||
|
false);
|
||||||
|
|
||||||
int sessionCount = 0;
|
int sessionCount = 0;
|
||||||
|
|
||||||
@ -111,7 +118,7 @@ public class ConcurrentSessionControllerImpl implements ConcurrentSessionControl
|
|||||||
|
|
||||||
int allowableSessions = getMaximumSessionsForThisUser(request);
|
int allowableSessions = getMaximumSessionsForThisUser(request);
|
||||||
Assert.isTrue(allowableSessions != 0,
|
Assert.isTrue(allowableSessions != 0,
|
||||||
"getMaximumSessionsForThisUser() must return either -1 to allow unlimited logins, or a positive integer to specify a maximum");
|
"getMaximumSessionsForThisUser() must return either -1 to allow unlimited logins, or a positive integer to specify a maximum");
|
||||||
|
|
||||||
if (sessionCount < allowableSessions) {
|
if (sessionCount < allowableSessions) {
|
||||||
return;
|
return;
|
||||||
@ -124,41 +131,40 @@ public class ConcurrentSessionControllerImpl implements ConcurrentSessionControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allowableSessionsExceeded(sessionId, sessions,
|
allowableSessionsExceeded(sessionId, sessions, allowableSessions,
|
||||||
allowableSessions, sessionRegistry);
|
sessionRegistry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method intended for use by subclasses to override the maximum
|
* Method intended for use by subclasses to override the maximum number of
|
||||||
* number of sessions that are permitted for a particular
|
* sessions that are permitted for a particular authentication. The
|
||||||
* authentication. The default implementation simply returns the
|
* default implementation simply returns the <code>maximumSessions</code>
|
||||||
* <code>maximumSessions</code> value for the bean.
|
* value for the bean.
|
||||||
*
|
*
|
||||||
* @param authentication to determine the maximum sessions for
|
* @param authentication to determine the maximum sessions for
|
||||||
* @return either -1 meaning unlimited, or a positive integer to
|
*
|
||||||
* limit (never zero)
|
* @return either -1 meaning unlimited, or a positive integer to limit
|
||||||
|
* (never zero)
|
||||||
*/
|
*/
|
||||||
protected int getMaximumSessionsForThisUser(
|
protected int getMaximumSessionsForThisUser(Authentication authentication) {
|
||||||
Authentication authentication) {
|
|
||||||
return maximumSessions;
|
return maximumSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerSuccessfulAuthentication(
|
public void registerSuccessfulAuthentication(Authentication authentication) {
|
||||||
Authentication authentication) {
|
|
||||||
Assert.notNull(authentication,
|
Assert.notNull(authentication,
|
||||||
"Authentication cannot be null (violation of interface contract)");
|
"Authentication cannot be null (violation of interface contract)");
|
||||||
|
|
||||||
Object principal = SessionRegistryUtils
|
Object principal = SessionRegistryUtils
|
||||||
.obtainPrincipalFromAuthentication(authentication);
|
.obtainPrincipalFromAuthentication(authentication);
|
||||||
String sessionId = SessionRegistryUtils
|
String sessionId = SessionRegistryUtils
|
||||||
.obtainSessionIdFromAuthentication(authentication);
|
.obtainSessionIdFromAuthentication(authentication);
|
||||||
|
|
||||||
sessionRegistry.removeSessionInformation(sessionId);
|
sessionRegistry.removeSessionInformation(sessionId);
|
||||||
sessionRegistry.registerNewSession(sessionId, principal);
|
sessionRegistry.registerNewSession(sessionId, principal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExceptionIfMaximumExceeded(
|
public void setExceptionIfMaximumExceeded(
|
||||||
boolean exceptionIfMaximumExceeded) {
|
boolean exceptionIfMaximumExceeded) {
|
||||||
this.exceptionIfMaximumExceeded = exceptionIfMaximumExceeded;
|
this.exceptionIfMaximumExceeded = exceptionIfMaximumExceeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,8 +176,7 @@ public class ConcurrentSessionControllerImpl implements ConcurrentSessionControl
|
|||||||
this.messages = new MessageSourceAccessor(messageSource);
|
this.messages = new MessageSourceAccessor(messageSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSessionRegistry(
|
public void setSessionRegistry(SessionRegistry sessionRegistry) {
|
||||||
SessionRegistry sessionRegistry) {
|
|
||||||
this.sessionRegistry = sessionRegistry;
|
this.sessionRegistry = sessionRegistry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,15 +34,20 @@ public interface SessionRegistry {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains all the known sessions for the specified principal. Sessions
|
* Obtains all the known sessions for the specified principal. Sessions
|
||||||
* that have expired or destroyed are not returned.
|
* that have been destroyed are not returned. Sessions that have expired
|
||||||
|
* may be returned, depending on the passed argument.
|
||||||
*
|
*
|
||||||
* @param principal to locate sessions for (should never be
|
* @param principal to locate sessions for (should never be
|
||||||
* <code>null</code>)
|
* <code>null</code>)
|
||||||
|
* @param includeExpiredSessions if <code>true</code>, the returned
|
||||||
|
* sessions will also include those that have expired for the
|
||||||
|
* principal
|
||||||
*
|
*
|
||||||
* @return the unexpired and undestroyed sessions for this principal, or
|
* @return the matching sessions for this principal, or <code>null</code>
|
||||||
* <code>null</code> if none were found
|
* if none were found
|
||||||
*/
|
*/
|
||||||
public SessionInformation[] getAllSessions(Object principal);
|
public SessionInformation[] getAllSessions(Object principal,
|
||||||
|
boolean includeExpiredSessions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the session information for the specified
|
* Obtains the session information for the specified
|
||||||
|
@ -64,7 +64,8 @@ public class SessionRegistryImpl implements SessionRegistry,
|
|||||||
return principals.keySet().toArray();
|
return principals.keySet().toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SessionInformation[] getAllSessions(Object principal) {
|
public SessionInformation[] getAllSessions(Object principal,
|
||||||
|
boolean includeExpiredSessions) {
|
||||||
Set sessionsUsedByPrincipal = (Set) principals.get(principal);
|
Set sessionsUsedByPrincipal = (Set) principals.get(principal);
|
||||||
|
|
||||||
if (sessionsUsedByPrincipal == null) {
|
if (sessionsUsedByPrincipal == null) {
|
||||||
@ -79,7 +80,7 @@ public class SessionRegistryImpl implements SessionRegistry,
|
|||||||
String sessionId = (String) iter.next();
|
String sessionId = (String) iter.next();
|
||||||
SessionInformation sessionInformation = getSessionInformation(sessionId);
|
SessionInformation sessionInformation = getSessionInformation(sessionId);
|
||||||
|
|
||||||
if (!sessionInformation.isExpired()) {
|
if (includeExpiredSessions || !sessionInformation.isExpired()) {
|
||||||
list.add(sessionInformation);
|
list.add(sessionInformation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user