From 9d213f46a40b49dd3f22fe4969bd4a8a5eac6154 Mon Sep 17 00:00:00 2001 From: Ben Alex Date: Wed, 8 Feb 2006 04:42:03 +0000 Subject: [PATCH] SEC-168: Prevent errors with concurrent session support. --- .../AnonymousAuthenticationToken.java | 77 ++++++---- .../anonymous/AnonymousProcessingFilter.java | 142 ++++++++++-------- 2 files changed, 124 insertions(+), 95 deletions(-) diff --git a/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationToken.java b/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationToken.java index 1cd660e5c1..95ca9ebdf5 100644 --- a/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationToken.java +++ b/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationToken.java @@ -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"); * you may not use this file except in compliance with the License. @@ -16,9 +16,8 @@ package org.acegisecurity.providers.anonymous; import org.acegisecurity.GrantedAuthority; -import org.acegisecurity.providers.AbstractAuthenticationToken; -import org.springframework.util.Assert; +import org.acegisecurity.providers.AbstractAuthenticationToken; import java.io.Serializable; @@ -33,6 +32,7 @@ public class AnonymousAuthenticationToken extends AbstractAuthenticationToken implements Serializable { //~ Instance fields ======================================================== + private Object details; private Object principal; private boolean authenticated; private int keyHash; @@ -50,7 +50,6 @@ public class AnonymousAuthenticationToken extends AbstractAuthenticationToken */ public AnonymousAuthenticationToken(String key, Object principal, GrantedAuthority[] authorities) { - super(authorities); if ((key == null) || ("".equals(key)) || (principal == null) @@ -62,36 +61,11 @@ public class AnonymousAuthenticationToken extends AbstractAuthenticationToken this.keyHash = key.hashCode(); this.principal = principal; - this.authenticated = true; + this.authenticated = true; } //~ Methods ================================================================ - public void setAuthenticated(boolean isAuthenticated) { - this.authenticated = isAuthenticated; - } - - public boolean isAuthenticated() { - return this.authenticated; - } - - /** - * Always returns an empty String - * - * @return an empty String - */ - public Object getCredentials() { - return ""; - } - - public int getKeyHash() { - return this.keyHash; - } - - public Object getPrincipal() { - return this.principal; - } - public boolean equals(Object obj) { if (!super.equals(obj)) { return false; @@ -104,9 +78,50 @@ public class AnonymousAuthenticationToken extends AbstractAuthenticationToken return false; } - return true; + if ((this.details == null) && (test.getDetails() != null)) { + return false; + } + + if ((this.details != null) && (test.getDetails() == null)) { + return false; + } + + return this.details.equals(test.getDetails()); } return false; } + + /** + * Always returns an empty String + * + * @return an empty String + */ + public Object getCredentials() { + return ""; + } + + public Object getDetails() { + return details; + } + + public int getKeyHash() { + return this.keyHash; + } + + public Object getPrincipal() { + return this.principal; + } + + public boolean isAuthenticated() { + return this.authenticated; + } + + public void setAuthenticated(boolean isAuthenticated) { + this.authenticated = isAuthenticated; + } + + public void setDetails(Object details) { + this.details = details; + } } diff --git a/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousProcessingFilter.java b/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousProcessingFilter.java index 3b5500d7a7..57a60acf23 100644 --- a/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousProcessingFilter.java @@ -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"); * you may not use this file except in compliance with the License. @@ -16,7 +16,11 @@ package org.acegisecurity.providers.anonymous; import org.acegisecurity.Authentication; + import org.acegisecurity.context.SecurityContextHolder; + +import org.acegisecurity.ui.WebAuthenticationDetails; + import org.acegisecurity.userdetails.memory.UserAttribute; import org.apache.commons.logging.Log; @@ -34,6 +38,7 @@ import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; /** @@ -62,52 +67,41 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean { //~ Methods ================================================================ - public void setKey(String key) { - this.key = key; - } - - public String getKey() { - return key; - } - - /** - * Controls whether the filter will remove the Anonymous token after the - * request is complete. Generally this is desired to avoid the expense of - * a session being created by {@link - * org.acegisecurity.context.HttpSessionContextIntegrationFilter - * HttpSessionContextIntegrationFilter} simply to store the Anonymous - * authentication token. - * - *

- * Defaults to true, being the most optimal and appropriate - * option (ie AnonymousProcessingFilter will clear the token - * at the end of each request, thus avoiding the session creation overhead - * in a typical configuration. - *

- * - * @param removeAfterRequest DOCUMENT ME! - */ - public void setRemoveAfterRequest(boolean removeAfterRequest) { - this.removeAfterRequest = removeAfterRequest; - } - - public boolean isRemoveAfterRequest() { - return removeAfterRequest; - } - - public void setUserAttribute(UserAttribute userAttributeDefinition) { - this.userAttribute = userAttributeDefinition; - } - - public UserAttribute getUserAttribute() { - return userAttribute; - } - public void afterPropertiesSet() throws Exception { Assert.notNull(userAttribute); Assert.hasLength(key); } + /** + * Enables subclasses to determine whether or not an anonymous + * authentication token should be setup for this request. This is useful + * if anonymous authentication should be allowed only for specific IP + * subnet ranges etc. + * + * @param request to assist the method determine request details + * + * @return true if the anonymous token should be setup for + * this request (provided that the request doesn't already have + * some other Authentication inside it), or + * false if no anonymous token should be setup for + * this request + */ + protected boolean applyAnonymousForThisRequest(ServletRequest request) { + return true; + } + + protected Authentication createAuthentication(ServletRequest request) { + Assert.isInstanceOf(HttpServletRequest.class, request, + "ServletRequest must be an instance of HttpServletRequest"); + + AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(key, + userAttribute.getPassword(), userAttribute.getAuthorities()); + auth.setDetails(new WebAuthenticationDetails( + (HttpServletRequest) request)); + + return auth; + } + /** * Does nothing - we reply on IoC lifecycle services instead. */ @@ -119,7 +113,8 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean { if (applyAnonymousForThisRequest(request)) { if (SecurityContextHolder.getContext().getAuthentication() == null) { - SecurityContextHolder.getContext().setAuthentication(createAuthentication( + SecurityContextHolder.getContext() + .setAuthentication(createAuthentication( request)); addedToken = true; @@ -143,13 +138,22 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean { chain.doFilter(request, response); } finally { if (addedToken && removeAfterRequest - && createAuthentication(request).equals(SecurityContextHolder.getContext() - .getAuthentication())) { + && createAuthentication(request) + .equals(SecurityContextHolder.getContext() + .getAuthentication())) { SecurityContextHolder.getContext().setAuthentication(null); } } } + public String getKey() { + return key; + } + + public UserAttribute getUserAttribute() { + return userAttribute; + } + /** * Does nothing - we reply on IoC lifecycle services instead. * @@ -159,26 +163,36 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean { */ public void init(FilterConfig ignored) throws ServletException {} - /** - * Enables subclasses to determine whether or not an anonymous - * authentication token should be setup for this request. This is useful - * if anonymous authentication should be allowed only for specific IP - * subnet ranges etc. - * - * @param request to assist the method determine request details - * - * @return true if the anonymous token should be setup for - * this request (provided that the request doesn't already have - * some other Authentication inside it), or - * false if no anonymous token should be setup for - * this request - */ - protected boolean applyAnonymousForThisRequest(ServletRequest request) { - return true; + public boolean isRemoveAfterRequest() { + return removeAfterRequest; } - protected Authentication createAuthentication(ServletRequest request) { - return new AnonymousAuthenticationToken(key, - userAttribute.getPassword(), userAttribute.getAuthorities()); + public void setKey(String key) { + this.key = key; + } + + /** + * Controls whether the filter will remove the Anonymous token after the + * request is complete. Generally this is desired to avoid the expense of + * a session being created by {@link + * org.acegisecurity.context.HttpSessionContextIntegrationFilter + * HttpSessionContextIntegrationFilter} simply to store the Anonymous + * authentication token. + * + *

+ * Defaults to true, being the most optimal and appropriate + * option (ie AnonymousProcessingFilter will clear the token + * at the end of each request, thus avoiding the session creation overhead + * in a typical configuration. + *

+ * + * @param removeAfterRequest DOCUMENT ME! + */ + public void setRemoveAfterRequest(boolean removeAfterRequest) { + this.removeAfterRequest = removeAfterRequest; + } + + public void setUserAttribute(UserAttribute userAttributeDefinition) { + this.userAttribute = userAttributeDefinition; } }