Anonymous principal support. As requested by the community at various times, including in http://forum.springframework.org/viewtopic.php?t=1925.
This commit is contained in:
parent
3c4faf58c7
commit
693ac5a24a
|
@ -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.
|
||||||
|
@ -32,10 +32,14 @@ public interface AccessDecisionManager {
|
||||||
* @param config the configuration attributes associated with the secured
|
* @param config the configuration attributes associated with the secured
|
||||||
* object being invoked
|
* object being invoked
|
||||||
*
|
*
|
||||||
* @throws AccessDeniedException if access is denied
|
* @throws AccessDeniedException if access is denied as the authentication
|
||||||
|
* does not hold a required authority or ACL privilege
|
||||||
|
* @throws InsufficientAuthenticationException if access is denied as the
|
||||||
|
* authentication does not provide a sufficient level of trust
|
||||||
*/
|
*/
|
||||||
public void decide(Authentication authentication, Object object,
|
public void decide(Authentication authentication, Object object,
|
||||||
ConfigAttributeDefinition config) throws AccessDeniedException;
|
ConfigAttributeDefinition config)
|
||||||
|
throws AccessDeniedException, InsufficientAuthenticationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this <code>AccessDecisionManager</code> is able to
|
* Indicates whether this <code>AccessDecisionManager</code> is able to
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -16,9 +16,8 @@
|
||||||
package net.sf.acegisecurity;
|
package net.sf.acegisecurity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract superclass for all exceptions related to the {@link
|
* Abstract superclass for all exceptions related an {@link Authentication}
|
||||||
* AuthenticationManager} being unable to authenticate an {@link
|
* object being invalid for whatever reason.
|
||||||
* Authentication} object.
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
|
@ -57,11 +56,11 @@ public abstract class AuthenticationException extends AcegiSecurityException {
|
||||||
|
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
void setAuthentication(Authentication authentication) {
|
|
||||||
this.authentication = authentication;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Authentication getAuthentication() {
|
public Authentication getAuthentication() {
|
||||||
return authentication;
|
return authentication;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setAuthentication(Authentication authentication) {
|
||||||
|
this.authentication = authentication;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates <code>Authentication</code> tokens
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public interface AuthenticationTrustResolver {
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the passed <code>Authentication</code> token
|
||||||
|
* represents an anonymous user. Typically the framework will call this
|
||||||
|
* method if it is trying to decide whether an
|
||||||
|
* <code>AccessDeniedException</code> should result in a final rejection
|
||||||
|
* (ie as would be the case if the principal was non-anonymous/fully
|
||||||
|
* authenticated) or direct the principal to attempt actual authentication
|
||||||
|
* (ie as would be the case if the <code>Authentication</code> was merely
|
||||||
|
* anonymous).
|
||||||
|
*
|
||||||
|
* @param authentication to test (may be <code>null</code> in which case
|
||||||
|
* the method will always return <code>false</code>)
|
||||||
|
*
|
||||||
|
* @return <code>true</code> the passed authentication token represented an
|
||||||
|
* anonymous principal, <code>false</code> otherwise
|
||||||
|
*/
|
||||||
|
public boolean isAnonymous(Authentication authentication);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the passed <code>Authentication</code> token
|
||||||
|
* represents user that has been remembered (ie not a user that has been
|
||||||
|
* fully authenticated).
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <b>No part of the framework uses this method</b>, as it is a weak
|
||||||
|
* definition of trust levels. The method is provided simply to assist
|
||||||
|
* with custom <code>AccessDecisionVoter</code>s and the like that you
|
||||||
|
* might develop. Of course, you don't need to use this method either and
|
||||||
|
* can develop your own "trust level" hierarchy instead.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param authentication to test (may be <code>null</code> in which case
|
||||||
|
* the method will always return <code>false</code>)
|
||||||
|
*
|
||||||
|
* @return <code>true</code> the passed authentication token represented a
|
||||||
|
* principal authenticated using a remember-me token,
|
||||||
|
* <code>false</code> otherwise
|
||||||
|
*/
|
||||||
|
public boolean isRememberMe(Authentication authentication);
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic implementation of {@link AuthenticationTrustResolverImpl}.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Makes trust decisions based on whether the passed
|
||||||
|
* <code>Authentication</code> is an instance of a defined class.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If {@link #anonymousClass} or {@link #rememberMeClass} is <code>null</code>,
|
||||||
|
* the corresponding method will always return <code>false</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AuthenticationTrustResolverImpl
|
||||||
|
implements AuthenticationTrustResolver {
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private Class anonymousClass = AnonymousAuthenticationToken.class;
|
||||||
|
private Class rememberMeClass;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public boolean isAnonymous(Authentication authentication) {
|
||||||
|
if ((anonymousClass == null) || (authentication == null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return anonymousClass.isAssignableFrom(authentication.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnonymousClass(Class anonymousClass) {
|
||||||
|
this.anonymousClass = anonymousClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getAnonymousClass() {
|
||||||
|
return anonymousClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRememberMe(Authentication authentication) {
|
||||||
|
if ((rememberMeClass == null) || (authentication == null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rememberMeClass.isAssignableFrom(authentication.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRememberMeClass(Class rememberMeClass) {
|
||||||
|
this.rememberMeClass = rememberMeClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getRememberMeClass() {
|
||||||
|
return rememberMeClass;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown if an authentication request is rejected because the credentials are
|
||||||
|
* not sufficiently trusted.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* {{@link net.sf.acegisecurity.vote.AccessDecisionVoter}s will typically throw
|
||||||
|
* this exception if they are dissatisfied with the level of the
|
||||||
|
* authentication, such as if performed using a remember-me mechnanism or
|
||||||
|
* anonymously. The commonly used {@link
|
||||||
|
* net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter} will thus
|
||||||
|
* cause the <code>AuthenticationEntryPoint</code> to be called, allowing the
|
||||||
|
* principal to authenticate with a stronger level of authentication. }
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class InsufficientAuthenticationException extends AuthenticationException {
|
||||||
|
//~ Constructors ===========================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an <code>InsufficientAuthenticationException</code> with the
|
||||||
|
* specified message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message
|
||||||
|
*/
|
||||||
|
public InsufficientAuthenticationException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an <code>InsufficientAuthenticationException</code> with the
|
||||||
|
* specified message and root cause.
|
||||||
|
*
|
||||||
|
* @param msg the detail message
|
||||||
|
* @param t root cause
|
||||||
|
*/
|
||||||
|
public InsufficientAuthenticationException(String msg, Throwable t) {
|
||||||
|
super(msg, t);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,6 +17,9 @@ package net.sf.acegisecurity.intercept.web;
|
||||||
|
|
||||||
import net.sf.acegisecurity.AccessDeniedException;
|
import net.sf.acegisecurity.AccessDeniedException;
|
||||||
import net.sf.acegisecurity.AuthenticationException;
|
import net.sf.acegisecurity.AuthenticationException;
|
||||||
|
import net.sf.acegisecurity.AuthenticationTrustResolver;
|
||||||
|
import net.sf.acegisecurity.AuthenticationTrustResolverImpl;
|
||||||
|
import net.sf.acegisecurity.context.security.SecureContextUtils;
|
||||||
import net.sf.acegisecurity.ui.AbstractProcessingFilter;
|
import net.sf.acegisecurity.ui.AbstractProcessingFilter;
|
||||||
import net.sf.acegisecurity.util.PortResolver;
|
import net.sf.acegisecurity.util.PortResolver;
|
||||||
import net.sf.acegisecurity.util.PortResolverImpl;
|
import net.sf.acegisecurity.util.PortResolverImpl;
|
||||||
|
@ -26,6 +29,8 @@ import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.Filter;
|
import javax.servlet.Filter;
|
||||||
|
@ -54,10 +59,13 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* If an {@link AccessDeniedException} is detected, the filter will respond
|
* If an {@link AccessDeniedException} is detected, the filter will determine
|
||||||
* with a <code>HttpServletResponse.SC_FORBIDDEN</code> (403 error). In
|
* whether or not the user is an anonymous user. If they are an anonymous
|
||||||
* addition, the <code>AccessDeniedException</code> itself will be placed in
|
* user, the <code>authenticationEntryPoint</code> will be launched. If they
|
||||||
* the <code>HttpSession</code> attribute keyed against {@link
|
* are not an anonymous user, the filter will respond with a
|
||||||
|
* <code>HttpServletResponse.SC_FORBIDDEN</code> (403 error). In addition,
|
||||||
|
* the <code>AccessDeniedException</code> itself will be placed in the
|
||||||
|
* <code>HttpSession</code> attribute keyed against {@link
|
||||||
* #ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY} (to allow access to the stack
|
* #ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY} (to allow access to the stack
|
||||||
* trace etc). Again, this allows common access denied handling irrespective
|
* trace etc). Again, this allows common access denied handling irrespective
|
||||||
* of the originating security interceptor.
|
* of the originating security interceptor.
|
||||||
|
@ -104,6 +112,7 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||||
|
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
||||||
private FilterSecurityInterceptor filterSecurityInterceptor;
|
private FilterSecurityInterceptor filterSecurityInterceptor;
|
||||||
private PortResolver portResolver = new PortResolverImpl();
|
private PortResolver portResolver = new PortResolverImpl();
|
||||||
|
|
||||||
|
@ -118,6 +127,15 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
|
||||||
return authenticationEntryPoint;
|
return authenticationEntryPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAuthenticationTrustResolver(
|
||||||
|
AuthenticationTrustResolver authenticationTrustResolver) {
|
||||||
|
this.authenticationTrustResolver = authenticationTrustResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationTrustResolver getAuthenticationTrustResolver() {
|
||||||
|
return authenticationTrustResolver;
|
||||||
|
}
|
||||||
|
|
||||||
public void setFilterSecurityInterceptor(
|
public void setFilterSecurityInterceptor(
|
||||||
FilterSecurityInterceptor filterSecurityInterceptor) {
|
FilterSecurityInterceptor filterSecurityInterceptor) {
|
||||||
this.filterSecurityInterceptor = filterSecurityInterceptor;
|
this.filterSecurityInterceptor = filterSecurityInterceptor;
|
||||||
|
@ -136,19 +154,13 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
if (authenticationEntryPoint == null) {
|
Assert.notNull(authenticationEntryPoint,
|
||||||
throw new IllegalArgumentException(
|
"authenticationEntryPoint must be specified");
|
||||||
"authenticationEntryPoint must be specified");
|
Assert.notNull(filterSecurityInterceptor,
|
||||||
}
|
"filterSecurityInterceptor must be specified");
|
||||||
|
Assert.notNull(portResolver, "portResolver must be specified");
|
||||||
if (filterSecurityInterceptor == null) {
|
Assert.notNull(authenticationTrustResolver,
|
||||||
throw new IllegalArgumentException(
|
"authenticationTrustResolver must be specified");
|
||||||
"filterSecurityInterceptor must be specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (portResolver == null) {
|
|
||||||
throw new IllegalArgumentException("portResolver must be specified");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {}
|
public void destroy() {}
|
||||||
|
@ -172,43 +184,29 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
|
||||||
logger.debug("Chain processed normally");
|
logger.debug("Chain processed normally");
|
||||||
}
|
}
|
||||||
} catch (AuthenticationException authentication) {
|
} catch (AuthenticationException authentication) {
|
||||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
|
||||||
|
|
||||||
int port = portResolver.getServerPort(request);
|
|
||||||
boolean includePort = true;
|
|
||||||
|
|
||||||
if ("http".equals(request.getScheme().toLowerCase())
|
|
||||||
&& (port == 80)) {
|
|
||||||
includePort = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("https".equals(request.getScheme().toLowerCase())
|
|
||||||
&& (port == 443)) {
|
|
||||||
includePort = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String targetUrl = request.getScheme() + "://"
|
|
||||||
+ request.getServerName() + ((includePort) ? (":" + port) : "")
|
|
||||||
+ httpRequest.getContextPath() + fi.getRequestUrl();
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(
|
logger.debug("Authentication exception occurred; redirecting to authentication entry point",
|
||||||
"Authentication failed - adding target URL to Session: "
|
authentication);
|
||||||
+ targetUrl, authentication);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
((HttpServletRequest) request).getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY,
|
sendStartAuthentication(fi, authentication);
|
||||||
targetUrl);
|
|
||||||
authenticationEntryPoint.commence(request, response, authentication);
|
|
||||||
} catch (AccessDeniedException accessDenied) {
|
} catch (AccessDeniedException accessDenied) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (authenticationTrustResolver.isAnonymous(
|
||||||
logger.debug(
|
SecureContextUtils.getSecureContext().getAuthentication())) {
|
||||||
"Access is denied - sending back forbidden response");
|
if (logger.isDebugEnabled()) {
|
||||||
}
|
logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point",
|
||||||
|
accessDenied);
|
||||||
|
}
|
||||||
|
|
||||||
((HttpServletRequest) request).getSession().setAttribute(ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY,
|
sendStartAuthentication(fi, null);
|
||||||
accessDenied);
|
} else {
|
||||||
sendAccessDeniedError(request, response, accessDenied);
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Access is denied (user is not anonymous); sending back forbidden response",
|
||||||
|
accessDenied);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendAccessDeniedError(fi, accessDenied);
|
||||||
|
}
|
||||||
} catch (Throwable otherException) {
|
} catch (Throwable otherException) {
|
||||||
throw new ServletException(otherException);
|
throw new ServletException(otherException);
|
||||||
}
|
}
|
||||||
|
@ -216,19 +214,43 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
|
||||||
|
|
||||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||||
|
|
||||||
/**
|
protected void sendAccessDeniedError(FilterInvocation fi,
|
||||||
* Allows subclasses to override if required
|
AccessDeniedException accessDenied)
|
||||||
*
|
throws ServletException, IOException {
|
||||||
* @param request
|
((HttpServletRequest) fi.getRequest()).getSession().setAttribute(ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY,
|
||||||
* @param response
|
accessDenied);
|
||||||
* @param accessDenied
|
((HttpServletResponse) fi.getResponse()).sendError(HttpServletResponse.SC_FORBIDDEN,
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
protected void sendAccessDeniedError(ServletRequest request,
|
|
||||||
ServletResponse response, AccessDeniedException accessDenied)
|
|
||||||
throws IOException {
|
|
||||||
((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN,
|
|
||||||
accessDenied.getMessage()); // 403
|
accessDenied.getMessage()); // 403
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void sendStartAuthentication(FilterInvocation fi,
|
||||||
|
AuthenticationException reason) throws ServletException, IOException {
|
||||||
|
HttpServletRequest request = (HttpServletRequest) fi.getRequest();
|
||||||
|
|
||||||
|
int port = portResolver.getServerPort(request);
|
||||||
|
boolean includePort = true;
|
||||||
|
|
||||||
|
if ("http".equals(request.getScheme().toLowerCase()) && (port == 80)) {
|
||||||
|
includePort = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("https".equals(request.getScheme().toLowerCase()) && (port == 443)) {
|
||||||
|
includePort = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String targetUrl = request.getScheme() + "://"
|
||||||
|
+ request.getServerName() + ((includePort) ? (":" + port) : "")
|
||||||
|
+ request.getContextPath() + fi.getRequestUrl();
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"Authentication entry point being called; target URL added to Session: "
|
||||||
|
+ targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
((HttpServletRequest) request).getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY,
|
||||||
|
targetUrl);
|
||||||
|
authenticationEntryPoint.commence(request,
|
||||||
|
(HttpServletResponse) fi.getResponse(), reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
/* 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.anonymous;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.AuthenticationException;
|
||||||
|
import net.sf.acegisecurity.BadCredentialsException;
|
||||||
|
import net.sf.acegisecurity.providers.AuthenticationProvider;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link AuthenticationProvider} implementation that validates {@link
|
||||||
|
* net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationToken}s.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* To be successfully validated, the {@link
|
||||||
|
* net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationToken#getKeyHash()}
|
||||||
|
* must match this class' {@link #getKey()}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AnonymousAuthenticationProvider implements AuthenticationProvider,
|
||||||
|
InitializingBean {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AnonymousAuthenticationProvider.class);
|
||||||
|
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void setKey(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
Assert.hasLength(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Authentication authenticate(Authentication authentication)
|
||||||
|
throws AuthenticationException {
|
||||||
|
if (!supports(authentication.getClass())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.key.hashCode() != ((AnonymousAuthenticationToken) authentication)
|
||||||
|
.getKeyHash()) {
|
||||||
|
throw new BadCredentialsException(
|
||||||
|
"The presented AnonymousAuthenticationToken does not contain the expected key");
|
||||||
|
}
|
||||||
|
|
||||||
|
return authentication;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supports(Class authentication) {
|
||||||
|
return (AnonymousAuthenticationToken.class.isAssignableFrom(authentication));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
/* 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.anonymous;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.GrantedAuthority;
|
||||||
|
import net.sf.acegisecurity.providers.AbstractAuthenticationToken;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an anonymous <code>Authentication</code>.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AnonymousAuthenticationToken extends AbstractAuthenticationToken
|
||||||
|
implements Serializable {
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private Object principal;
|
||||||
|
private GrantedAuthority[] authorities;
|
||||||
|
private int keyHash;
|
||||||
|
|
||||||
|
//~ Constructors ===========================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param key to identify if this object made by an authorised client
|
||||||
|
* @param principal the principal (typically a <code>UserDetails</code>)
|
||||||
|
* @param authorities the authorities granted to the principal
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if a <code>null</code> was passed
|
||||||
|
*/
|
||||||
|
public AnonymousAuthenticationToken(String key, Object principal,
|
||||||
|
GrantedAuthority[] authorities) {
|
||||||
|
if ((key == null) || ("".equals(key)) || (principal == null)
|
||||||
|
|| "".equals(principal) || (authorities == null)
|
||||||
|
|| (authorities.length == 0)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Cannot pass null or empty values to constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < authorities.length; i++) {
|
||||||
|
if (authorities[i] == null) {
|
||||||
|
throw new IllegalArgumentException("Granted authority element "
|
||||||
|
+ i
|
||||||
|
+ " is null - GrantedAuthority[] cannot contain any null elements");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.keyHash = key.hashCode();
|
||||||
|
this.principal = principal;
|
||||||
|
this.authorities = authorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AnonymousAuthenticationToken() {
|
||||||
|
throw new IllegalArgumentException("Cannot use default constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignored (always <code>true</code>).
|
||||||
|
*
|
||||||
|
* @param isAuthenticated ignored
|
||||||
|
*/
|
||||||
|
public void setAuthenticated(boolean isAuthenticated) {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Always returns <code>true</code>.
|
||||||
|
*
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
public boolean isAuthenticated() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GrantedAuthority[] getAuthorities() {
|
||||||
|
return this.authorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Always returns an empty <code>String</code>
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj instanceof AnonymousAuthenticationToken) {
|
||||||
|
AnonymousAuthenticationToken test = (AnonymousAuthenticationToken) obj;
|
||||||
|
|
||||||
|
if (this.getKeyHash() != test.getKeyHash()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,169 @@
|
||||||
|
/* 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.anonymous;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.context.security.SecureContext;
|
||||||
|
import net.sf.acegisecurity.context.security.SecureContextUtils;
|
||||||
|
import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint;
|
||||||
|
import net.sf.acegisecurity.providers.dao.memory.UserAttribute;
|
||||||
|
import net.sf.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects if there is no <code>Authentication</code> object in the
|
||||||
|
* <code>ContextHolder</code>, and populates it with one if needed.
|
||||||
|
*
|
||||||
|
* <P></p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* In summary, this filter is responsible for processing any request that has a
|
||||||
|
* HTTP request header of <code>Authorization</code> with an authentication
|
||||||
|
* scheme of <code>Basic</code> and a Base64-encoded
|
||||||
|
* <code>username:password</code> token. For example, to authenticate user
|
||||||
|
* "Aladdin" with password "open sesame" the following header would be
|
||||||
|
* presented:
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <code>Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This filter can be used to provide BASIC authentication services to both
|
||||||
|
* remoting protocol clients (such as Hessian and SOAP) as well as standard
|
||||||
|
* user agents (such as Internet Explorer and Netscape).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* If authentication is successful, the resulting {@link Authentication} object
|
||||||
|
* will be placed into the <code>ContextHolder</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If authentication fails, an {@link AuthenticationEntryPoint} implementation
|
||||||
|
* is called. Usually this should be {@link BasicProcessingFilterEntryPoint},
|
||||||
|
* which will prompt the user to authenticate again via BASIC authentication.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Basic authentication is an attractive protocol because it is simple and
|
||||||
|
* widely deployed. However, it still transmits a password in clear text and
|
||||||
|
* as such is undesirable in many situations. Digest authentication is also
|
||||||
|
* provided by Acegi Security and should be used instead of Basic
|
||||||
|
* authentication wherever possible. See {@link
|
||||||
|
* net.sf.acegisecurity.ui.digestauth.DigestProcessingFilter}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* <B>Do not use this class directly.</B> Instead configure
|
||||||
|
* <code>web.xml</code> to use the {@link
|
||||||
|
* net.sf.acegisecurity.util.FilterToBeanProxy}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AnonymousProcessingFilter implements Filter, InitializingBean {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AnonymousProcessingFilter.class);
|
||||||
|
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private String key;
|
||||||
|
private UserAttribute userAttribute;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void setKey(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserAttribute(UserAttribute userAttributeDefinition) {
|
||||||
|
this.userAttribute = userAttributeDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAttribute getUserAttribute() {
|
||||||
|
return userAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
Assert.notNull(userAttribute);
|
||||||
|
Assert.hasLength(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing - we reply on IoC lifecycle services instead.
|
||||||
|
*/
|
||||||
|
public void destroy() {}
|
||||||
|
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain chain) throws IOException, ServletException {
|
||||||
|
SecureContext sc = SecureContextUtils.getSecureContext();
|
||||||
|
|
||||||
|
if (sc.getAuthentication() == null) {
|
||||||
|
sc.setAuthentication(createAuthentication(request));
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Replaced ContextHolder with anonymous token: '"
|
||||||
|
+ sc.getAuthentication() + "'");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"ContextHolder not replaced with anonymous token, as ContextHolder already contained: '"
|
||||||
|
+ sc.getAuthentication() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing - we reply on IoC lifecycle services instead.
|
||||||
|
*
|
||||||
|
* @param arg0 DOCUMENT ME!
|
||||||
|
*
|
||||||
|
* @throws ServletException DOCUMENT ME!
|
||||||
|
*/
|
||||||
|
public void init(FilterConfig arg0) throws ServletException {}
|
||||||
|
|
||||||
|
protected Authentication createAuthentication(ServletRequest request) {
|
||||||
|
return new AnonymousAuthenticationToken(key,
|
||||||
|
userAttribute.getPassword(), userAttribute.getAuthorities());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Allows you to secure every invocation (especially useful for web request
|
||||||
|
URI security) by always having either an actual principal or an anonymous
|
||||||
|
principal authenticated.
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -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.
|
||||||
|
@ -29,7 +29,7 @@ import java.util.Vector;
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public class UserAttributeDefinition {
|
public class UserAttribute {
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
private List authorities = new Vector();
|
private List authorities = new Vector();
|
||||||
|
@ -38,7 +38,7 @@ public class UserAttributeDefinition {
|
||||||
|
|
||||||
//~ Constructors ===========================================================
|
//~ Constructors ===========================================================
|
||||||
|
|
||||||
public UserAttributeDefinition() {
|
public UserAttribute() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -23,8 +23,8 @@ import java.beans.PropertyEditorSupport;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property editor that creates a {@link UserAttributeDefinition} from a comma
|
* Property editor that creates a {@link UserAttribute} from a comma separated
|
||||||
* separated list of values.
|
* list of values.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
|
@ -37,7 +37,7 @@ public class UserAttributeEditor extends PropertyEditorSupport {
|
||||||
setValue(null);
|
setValue(null);
|
||||||
} else {
|
} else {
|
||||||
String[] tokens = StringUtils.commaDelimitedListToStringArray(s);
|
String[] tokens = StringUtils.commaDelimitedListToStringArray(s);
|
||||||
UserAttributeDefinition userAttrib = new UserAttributeDefinition();
|
UserAttribute userAttrib = new UserAttribute();
|
||||||
|
|
||||||
for (int i = 0; i < tokens.length; i++) {
|
for (int i = 0; i < tokens.length; i++) {
|
||||||
String currentToken = tokens[i];
|
String currentToken = tokens[i];
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -91,8 +91,7 @@ public class UserMapEditor extends PropertyEditorSupport {
|
||||||
// Convert value to a password, enabled setting, and list of granted authorities
|
// Convert value to a password, enabled setting, and list of granted authorities
|
||||||
configAttribEd.setAsText(value);
|
configAttribEd.setAsText(value);
|
||||||
|
|
||||||
UserAttributeDefinition attr = (UserAttributeDefinition) configAttribEd
|
UserAttribute attr = (UserAttribute) configAttribEd.getValue();
|
||||||
.getValue();
|
|
||||||
|
|
||||||
// Make a user object, assuming the properties were properly provided
|
// Make a user object, assuming the properties were properly provided
|
||||||
if (attr != null) {
|
if (attr != null) {
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.providers.TestingAuthenticationToken;
|
||||||
|
import net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link net.sf.acegisecurity.AuthenticationTrustResolverImpl}.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AuthenticationTrustResolverImplTests extends TestCase {
|
||||||
|
//~ Constructors ===========================================================
|
||||||
|
|
||||||
|
public AuthenticationTrustResolverImplTests() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationTrustResolverImplTests(String arg0) {
|
||||||
|
super(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
junit.textui.TestRunner.run(AuthenticationTrustResolverImplTests.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCorrectOperationIsAnonymous() {
|
||||||
|
AuthenticationTrustResolverImpl trustResolver = new AuthenticationTrustResolverImpl();
|
||||||
|
assertTrue(trustResolver.isAnonymous(
|
||||||
|
new AnonymousAuthenticationToken("ignored", "ignored",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ignored")})));
|
||||||
|
assertFalse(trustResolver.isAnonymous(
|
||||||
|
new TestingAuthenticationToken("ignored", "ignored",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ignored")})));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGettersSetters() {
|
||||||
|
AuthenticationTrustResolverImpl trustResolver = new AuthenticationTrustResolverImpl();
|
||||||
|
|
||||||
|
assertEquals(AnonymousAuthenticationToken.class,
|
||||||
|
trustResolver.getAnonymousClass());
|
||||||
|
trustResolver.setAnonymousClass(String.class);
|
||||||
|
assertEquals(String.class, trustResolver.getAnonymousClass());
|
||||||
|
|
||||||
|
assertNull(trustResolver.getRememberMeClass());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.
|
||||||
|
@ -19,11 +19,17 @@ import junit.framework.TestCase;
|
||||||
|
|
||||||
import net.sf.acegisecurity.AccessDeniedException;
|
import net.sf.acegisecurity.AccessDeniedException;
|
||||||
import net.sf.acegisecurity.BadCredentialsException;
|
import net.sf.acegisecurity.BadCredentialsException;
|
||||||
|
import net.sf.acegisecurity.GrantedAuthority;
|
||||||
|
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||||
import net.sf.acegisecurity.MockAuthenticationEntryPoint;
|
import net.sf.acegisecurity.MockAuthenticationEntryPoint;
|
||||||
import net.sf.acegisecurity.MockHttpServletRequest;
|
import net.sf.acegisecurity.MockHttpServletRequest;
|
||||||
import net.sf.acegisecurity.MockHttpServletResponse;
|
import net.sf.acegisecurity.MockHttpServletResponse;
|
||||||
import net.sf.acegisecurity.MockHttpSession;
|
import net.sf.acegisecurity.MockHttpSession;
|
||||||
import net.sf.acegisecurity.MockPortResolver;
|
import net.sf.acegisecurity.MockPortResolver;
|
||||||
|
import net.sf.acegisecurity.context.ContextHolder;
|
||||||
|
import net.sf.acegisecurity.context.security.SecureContext;
|
||||||
|
import net.sf.acegisecurity.context.security.SecureContextImpl;
|
||||||
|
import net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
|
||||||
import net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
|
import net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -62,8 +68,47 @@ public class SecurityEnforcementFilterTests extends TestCase {
|
||||||
junit.textui.TestRunner.run(SecurityEnforcementFilterTests.class);
|
junit.textui.TestRunner.run(SecurityEnforcementFilterTests.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAccessDeniedWhenAccessDeniedException()
|
public void testAccessDeniedWhenAnonymous() throws Exception {
|
||||||
throws Exception {
|
// Setup our HTTP request
|
||||||
|
HttpSession session = new MockHttpSession();
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest(null,
|
||||||
|
session);
|
||||||
|
request.setServletPath("/secure/page.html");
|
||||||
|
request.setServerPort(80);
|
||||||
|
request.setScheme("http");
|
||||||
|
request.setServerName("www.example.com");
|
||||||
|
request.setContextPath("/mycontext");
|
||||||
|
request.setRequestURL(
|
||||||
|
"http://www.example.com/mycontext/secure/page.html");
|
||||||
|
|
||||||
|
// Setup our expectation that the filter chain will not be invoked, as access is denied
|
||||||
|
MockFilterChain chain = new MockFilterChain(false);
|
||||||
|
|
||||||
|
// Setup the FilterSecurityInterceptor thrown an access denied exception
|
||||||
|
MockFilterSecurityInterceptor interceptor = new MockFilterSecurityInterceptor(true,
|
||||||
|
false);
|
||||||
|
|
||||||
|
// Setup ContextHolder, as filter needs to check if user is anonymous
|
||||||
|
SecureContext sc = new SecureContextImpl();
|
||||||
|
sc.setAuthentication(new AnonymousAuthenticationToken("ignored",
|
||||||
|
"ignored",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("IGNORED")}));
|
||||||
|
ContextHolder.setContext(sc);
|
||||||
|
|
||||||
|
// Test
|
||||||
|
SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
|
||||||
|
filter.setFilterSecurityInterceptor(interceptor);
|
||||||
|
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
|
||||||
|
"/login.jsp"));
|
||||||
|
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
filter.doFilter(request, response, chain);
|
||||||
|
assertEquals("/mycontext/login.jsp", response.getRedirect());
|
||||||
|
assertEquals("http://www.example.com/mycontext/secure/page.html",
|
||||||
|
request.getSession().getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAccessDeniedWhenNonAnonymous() throws Exception {
|
||||||
// Setup our HTTP request
|
// Setup our HTTP request
|
||||||
HttpSession session = new MockHttpSession();
|
HttpSession session = new MockHttpSession();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(null,
|
MockHttpServletRequest request = new MockHttpServletRequest(null,
|
||||||
|
@ -77,6 +122,11 @@ public class SecurityEnforcementFilterTests extends TestCase {
|
||||||
MockFilterSecurityInterceptor interceptor = new MockFilterSecurityInterceptor(true,
|
MockFilterSecurityInterceptor interceptor = new MockFilterSecurityInterceptor(true,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
// Setup ContextHolder, as filter needs to check if user is anonymous
|
||||||
|
SecureContext sc = new SecureContextImpl();
|
||||||
|
sc.setAuthentication(null);
|
||||||
|
ContextHolder.setContext(sc);
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
|
SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
|
||||||
filter.setFilterSecurityInterceptor(interceptor);
|
filter.setFilterSecurityInterceptor(interceptor);
|
||||||
|
@ -281,6 +331,11 @@ public class SecurityEnforcementFilterTests extends TestCase {
|
||||||
assertTrue(true);
|
assertTrue(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void tearDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
ContextHolder.setContext(null);
|
||||||
|
}
|
||||||
|
|
||||||
//~ Inner Classes ==========================================================
|
//~ Inner Classes ==========================================================
|
||||||
|
|
||||||
private class MockFilterChain implements FilterChain {
|
private class MockFilterChain implements FilterChain {
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
/* 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.anonymous;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.BadCredentialsException;
|
||||||
|
import net.sf.acegisecurity.GrantedAuthority;
|
||||||
|
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||||
|
import net.sf.acegisecurity.providers.TestingAuthenticationToken;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AnonymousAuthenticationProvider}.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AnonymousAuthenticationProviderTests extends TestCase {
|
||||||
|
//~ Constructors ===========================================================
|
||||||
|
|
||||||
|
public AnonymousAuthenticationProviderTests() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnonymousAuthenticationProviderTests(String arg0) {
|
||||||
|
super(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public final void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
junit.textui.TestRunner.run(AnonymousAuthenticationProviderTests.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetectsAnInvalidKey() throws Exception {
|
||||||
|
AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider();
|
||||||
|
aap.setKey("qwerty");
|
||||||
|
|
||||||
|
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("WRONG_KEY",
|
||||||
|
"Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
|
||||||
|
try {
|
||||||
|
Authentication result = aap.authenticate(token);
|
||||||
|
fail("Should have thrown BadCredentialsException");
|
||||||
|
} catch (BadCredentialsException expected) {
|
||||||
|
assertEquals("The presented AnonymousAuthenticationToken does not contain the expected key",
|
||||||
|
expected.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetectsMissingKey() throws Exception {
|
||||||
|
AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider();
|
||||||
|
|
||||||
|
try {
|
||||||
|
aap.afterPropertiesSet();
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGettersSetters() throws Exception {
|
||||||
|
AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider();
|
||||||
|
aap.setKey("qwerty");
|
||||||
|
aap.afterPropertiesSet();
|
||||||
|
assertEquals("qwerty", aap.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIgnoresClassesItDoesNotSupport() throws Exception {
|
||||||
|
AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider();
|
||||||
|
aap.setKey("qwerty");
|
||||||
|
|
||||||
|
TestingAuthenticationToken token = new TestingAuthenticationToken("user",
|
||||||
|
"password",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
|
||||||
|
assertFalse(aap.supports(TestingAuthenticationToken.class));
|
||||||
|
|
||||||
|
// Try it anyway
|
||||||
|
assertNull(aap.authenticate(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNormalOperation() throws Exception {
|
||||||
|
AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider();
|
||||||
|
aap.setKey("qwerty");
|
||||||
|
|
||||||
|
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("qwerty",
|
||||||
|
"Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
|
||||||
|
Authentication result = aap.authenticate(token);
|
||||||
|
|
||||||
|
assertEquals(result, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSupports() {
|
||||||
|
AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider();
|
||||||
|
assertTrue(aap.supports(AnonymousAuthenticationToken.class));
|
||||||
|
assertFalse(aap.supports(TestingAuthenticationToken.class));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,190 @@
|
||||||
|
/* 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.anonymous;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.GrantedAuthority;
|
||||||
|
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||||
|
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AnonymousAuthenticationToken}.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AnonymousAuthenticationTokenTests extends TestCase {
|
||||||
|
//~ Constructors ===========================================================
|
||||||
|
|
||||||
|
public AnonymousAuthenticationTokenTests() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnonymousAuthenticationTokenTests(String arg0) {
|
||||||
|
super(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public final void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
junit.textui.TestRunner.run(AnonymousAuthenticationTokenTests.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testConstructorRejectsNulls() {
|
||||||
|
try {
|
||||||
|
new AnonymousAuthenticationToken(null, "Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new AnonymousAuthenticationToken("key", null,
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new AnonymousAuthenticationToken("key", "Test", null);
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new AnonymousAuthenticationToken("key", "Test",
|
||||||
|
new GrantedAuthority[] {null});
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new AnonymousAuthenticationToken("key", "Test",
|
||||||
|
new GrantedAuthority[] {});
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEqualsWhenEqual() {
|
||||||
|
List proxyList1 = new Vector();
|
||||||
|
proxyList1.add("https://localhost/newPortal/j_acegi_cas_security_check");
|
||||||
|
|
||||||
|
AnonymousAuthenticationToken token1 = new AnonymousAuthenticationToken("key",
|
||||||
|
"Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
|
||||||
|
AnonymousAuthenticationToken token2 = new AnonymousAuthenticationToken("key",
|
||||||
|
"Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
|
||||||
|
assertEquals(token1, token2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetters() {
|
||||||
|
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("key",
|
||||||
|
"Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
|
||||||
|
assertEquals("key".hashCode(), token.getKeyHash());
|
||||||
|
assertEquals("Test", token.getPrincipal());
|
||||||
|
assertEquals("", token.getCredentials());
|
||||||
|
assertEquals("ROLE_ONE", token.getAuthorities()[0].getAuthority());
|
||||||
|
assertEquals("ROLE_TWO", token.getAuthorities()[1].getAuthority());
|
||||||
|
assertTrue(token.isAuthenticated());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNoArgConstructor() {
|
||||||
|
try {
|
||||||
|
new AnonymousAuthenticationToken();
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNotEqualsDueToAbstractParentEqualsCheck() {
|
||||||
|
AnonymousAuthenticationToken token1 = new AnonymousAuthenticationToken("key",
|
||||||
|
"Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
|
||||||
|
AnonymousAuthenticationToken token2 = new AnonymousAuthenticationToken("key",
|
||||||
|
"DIFFERENT_PRINCIPAL",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
|
||||||
|
assertFalse(token1.equals(token2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNotEqualsDueToDifferentAuthenticationClass() {
|
||||||
|
AnonymousAuthenticationToken token1 = new AnonymousAuthenticationToken("key",
|
||||||
|
"Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
|
||||||
|
UsernamePasswordAuthenticationToken token2 = new UsernamePasswordAuthenticationToken("Test",
|
||||||
|
"Password",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
token2.setAuthenticated(true);
|
||||||
|
|
||||||
|
assertFalse(token1.equals(token2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNotEqualsDueToKey() {
|
||||||
|
AnonymousAuthenticationToken token1 = new AnonymousAuthenticationToken("key",
|
||||||
|
"Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
|
||||||
|
AnonymousAuthenticationToken token2 = new AnonymousAuthenticationToken("DIFFERENT_KEY",
|
||||||
|
"Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
|
||||||
|
assertFalse(token1.equals(token2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSetAuthenticatedIgnored() {
|
||||||
|
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("key",
|
||||||
|
"Test",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||||
|
"ROLE_TWO")});
|
||||||
|
assertTrue(token.isAuthenticated());
|
||||||
|
token.setAuthenticated(false); // ignored
|
||||||
|
assertTrue(token.isAuthenticated());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,200 @@
|
||||||
|
/* 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.anonymous;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.GrantedAuthority;
|
||||||
|
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||||
|
import net.sf.acegisecurity.MockFilterConfig;
|
||||||
|
import net.sf.acegisecurity.MockHttpServletRequest;
|
||||||
|
import net.sf.acegisecurity.MockHttpServletResponse;
|
||||||
|
import net.sf.acegisecurity.context.ContextHolder;
|
||||||
|
import net.sf.acegisecurity.context.security.SecureContext;
|
||||||
|
import net.sf.acegisecurity.context.security.SecureContextImpl;
|
||||||
|
import net.sf.acegisecurity.context.security.SecureContextUtils;
|
||||||
|
import net.sf.acegisecurity.providers.TestingAuthenticationToken;
|
||||||
|
import net.sf.acegisecurity.providers.dao.memory.UserAttribute;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AnonymousProcessingFilter}.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AnonymousProcessingFilterTests extends TestCase {
|
||||||
|
//~ Constructors ===========================================================
|
||||||
|
|
||||||
|
public AnonymousProcessingFilterTests() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnonymousProcessingFilterTests(String arg0) {
|
||||||
|
super(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
junit.textui.TestRunner.run(AnonymousProcessingFilterTests.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetectsMissingKey() throws Exception {
|
||||||
|
UserAttribute user = new UserAttribute();
|
||||||
|
user.setPassword("anonymousUsername");
|
||||||
|
user.addAuthority(new GrantedAuthorityImpl("ROLE_ANONYMOUS"));
|
||||||
|
|
||||||
|
AnonymousProcessingFilter filter = new AnonymousProcessingFilter();
|
||||||
|
filter.setUserAttribute(user);
|
||||||
|
|
||||||
|
try {
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetectsUserAttribute() throws Exception {
|
||||||
|
AnonymousProcessingFilter filter = new AnonymousProcessingFilter();
|
||||||
|
filter.setKey("qwerty");
|
||||||
|
|
||||||
|
try {
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGettersSetters() throws Exception {
|
||||||
|
UserAttribute user = new UserAttribute();
|
||||||
|
user.setPassword("anonymousUsername");
|
||||||
|
user.addAuthority(new GrantedAuthorityImpl("ROLE_ANONYMOUS"));
|
||||||
|
|
||||||
|
AnonymousProcessingFilter filter = new AnonymousProcessingFilter();
|
||||||
|
filter.setKey("qwerty");
|
||||||
|
filter.setUserAttribute(user);
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
|
||||||
|
assertEquals("qwerty", filter.getKey());
|
||||||
|
assertEquals(user, filter.getUserAttribute());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOperationWhenAuthenticationExistsInContextHolder()
|
||||||
|
throws Exception {
|
||||||
|
// Put an Authentication object into the ContextHolder
|
||||||
|
SecureContext sc = SecureContextUtils.getSecureContext();
|
||||||
|
Authentication originalAuth = new TestingAuthenticationToken("user",
|
||||||
|
"password",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
|
||||||
|
sc.setAuthentication(originalAuth);
|
||||||
|
ContextHolder.setContext(sc);
|
||||||
|
|
||||||
|
// Setup our filter correctly
|
||||||
|
UserAttribute user = new UserAttribute();
|
||||||
|
user.setPassword("anonymousUsername");
|
||||||
|
user.addAuthority(new GrantedAuthorityImpl("ROLE_ANONYMOUS"));
|
||||||
|
|
||||||
|
AnonymousProcessingFilter filter = new AnonymousProcessingFilter();
|
||||||
|
filter.setKey("qwerty");
|
||||||
|
filter.setUserAttribute(user);
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
|
||||||
|
// Test
|
||||||
|
executeFilterInContainerSimulator(new MockFilterConfig(), filter,
|
||||||
|
new MockHttpServletRequest("x"), new MockHttpServletResponse(),
|
||||||
|
new MockFilterChain(true));
|
||||||
|
|
||||||
|
// Ensure filter didn't change our original object
|
||||||
|
assertEquals(originalAuth,
|
||||||
|
SecureContextUtils.getSecureContext().getAuthentication());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOperationWhenNoAuthenticationInContextHolder()
|
||||||
|
throws Exception {
|
||||||
|
UserAttribute user = new UserAttribute();
|
||||||
|
user.setPassword("anonymousUsername");
|
||||||
|
user.addAuthority(new GrantedAuthorityImpl("ROLE_ANONYMOUS"));
|
||||||
|
|
||||||
|
AnonymousProcessingFilter filter = new AnonymousProcessingFilter();
|
||||||
|
filter.setKey("qwerty");
|
||||||
|
filter.setUserAttribute(user);
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
|
||||||
|
executeFilterInContainerSimulator(new MockFilterConfig(), filter,
|
||||||
|
new MockHttpServletRequest("x"), new MockHttpServletResponse(),
|
||||||
|
new MockFilterChain(true));
|
||||||
|
|
||||||
|
Authentication auth = SecureContextUtils.getSecureContext()
|
||||||
|
.getAuthentication();
|
||||||
|
assertEquals("anonymousUsername", auth.getPrincipal());
|
||||||
|
assertEquals(new GrantedAuthorityImpl("ROLE_ANONYMOUS"),
|
||||||
|
auth.getAuthorities()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
ContextHolder.setContext(new SecureContextImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void tearDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
ContextHolder.setContext(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeFilterInContainerSimulator(FilterConfig filterConfig,
|
||||||
|
Filter filter, ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
filter.init(filterConfig);
|
||||||
|
filter.doFilter(request, response, filterChain);
|
||||||
|
filter.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ Inner Classes ==========================================================
|
||||||
|
|
||||||
|
private class MockFilterChain implements FilterChain {
|
||||||
|
private boolean expectToProceed;
|
||||||
|
|
||||||
|
public MockFilterChain(boolean expectToProceed) {
|
||||||
|
this.expectToProceed = expectToProceed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MockFilterChain() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
if (expectToProceed) {
|
||||||
|
assertTrue(true);
|
||||||
|
} else {
|
||||||
|
fail("Did not expect filter chain to proceed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.
|
||||||
|
@ -19,8 +19,7 @@ import junit.framework.TestCase;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link UserAttributeEditor} and associated {@link
|
* Tests {@link UserAttributeEditor} and associated {@link UserAttribute}.
|
||||||
* UserAttributeDefinition}.
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
|
@ -50,8 +49,7 @@ public class UserAttributeEditorTests extends TestCase {
|
||||||
UserAttributeEditor editor = new UserAttributeEditor();
|
UserAttributeEditor editor = new UserAttributeEditor();
|
||||||
editor.setAsText("password,ROLE_ONE,ROLE_TWO");
|
editor.setAsText("password,ROLE_ONE,ROLE_TWO");
|
||||||
|
|
||||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
UserAttribute user = (UserAttribute) editor.getValue();
|
||||||
.getValue();
|
|
||||||
assertTrue(user.isValid());
|
assertTrue(user.isValid());
|
||||||
assertTrue(user.isEnabled()); // default
|
assertTrue(user.isEnabled()); // default
|
||||||
assertEquals("password", user.getPassword());
|
assertEquals("password", user.getPassword());
|
||||||
|
@ -64,8 +62,7 @@ public class UserAttributeEditorTests extends TestCase {
|
||||||
UserAttributeEditor editor = new UserAttributeEditor();
|
UserAttributeEditor editor = new UserAttributeEditor();
|
||||||
editor.setAsText("password,disabled,ROLE_ONE,ROLE_TWO");
|
editor.setAsText("password,disabled,ROLE_ONE,ROLE_TWO");
|
||||||
|
|
||||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
UserAttribute user = (UserAttribute) editor.getValue();
|
||||||
.getValue();
|
|
||||||
assertTrue(user.isValid());
|
assertTrue(user.isValid());
|
||||||
assertTrue(!user.isEnabled());
|
assertTrue(!user.isEnabled());
|
||||||
assertEquals("password", user.getPassword());
|
assertEquals("password", user.getPassword());
|
||||||
|
@ -78,8 +75,7 @@ public class UserAttributeEditorTests extends TestCase {
|
||||||
UserAttributeEditor editor = new UserAttributeEditor();
|
UserAttributeEditor editor = new UserAttributeEditor();
|
||||||
editor.setAsText("");
|
editor.setAsText("");
|
||||||
|
|
||||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
UserAttribute user = (UserAttribute) editor.getValue();
|
||||||
.getValue();
|
|
||||||
assertTrue(user == null);
|
assertTrue(user == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,8 +83,7 @@ public class UserAttributeEditorTests extends TestCase {
|
||||||
UserAttributeEditor editor = new UserAttributeEditor();
|
UserAttributeEditor editor = new UserAttributeEditor();
|
||||||
editor.setAsText("password,ROLE_ONE,enabled,ROLE_TWO");
|
editor.setAsText("password,ROLE_ONE,enabled,ROLE_TWO");
|
||||||
|
|
||||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
UserAttribute user = (UserAttribute) editor.getValue();
|
||||||
.getValue();
|
|
||||||
assertTrue(user.isValid());
|
assertTrue(user.isValid());
|
||||||
assertTrue(user.isEnabled());
|
assertTrue(user.isEnabled());
|
||||||
assertEquals("password", user.getPassword());
|
assertEquals("password", user.getPassword());
|
||||||
|
@ -101,8 +96,7 @@ public class UserAttributeEditorTests extends TestCase {
|
||||||
UserAttributeEditor editor = new UserAttributeEditor();
|
UserAttributeEditor editor = new UserAttributeEditor();
|
||||||
editor.setAsText("MALFORMED_STRING");
|
editor.setAsText("MALFORMED_STRING");
|
||||||
|
|
||||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
UserAttribute user = (UserAttribute) editor.getValue();
|
||||||
.getValue();
|
|
||||||
assertTrue(user == null);
|
assertTrue(user == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,8 +104,7 @@ public class UserAttributeEditorTests extends TestCase {
|
||||||
UserAttributeEditor editor = new UserAttributeEditor();
|
UserAttributeEditor editor = new UserAttributeEditor();
|
||||||
editor.setAsText("disabled");
|
editor.setAsText("disabled");
|
||||||
|
|
||||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
UserAttribute user = (UserAttribute) editor.getValue();
|
||||||
.getValue();
|
|
||||||
assertTrue(user == null);
|
assertTrue(user == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,8 +112,7 @@ public class UserAttributeEditorTests extends TestCase {
|
||||||
UserAttributeEditor editor = new UserAttributeEditor();
|
UserAttributeEditor editor = new UserAttributeEditor();
|
||||||
editor.setAsText("password,enabled");
|
editor.setAsText("password,enabled");
|
||||||
|
|
||||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
UserAttribute user = (UserAttribute) editor.getValue();
|
||||||
.getValue();
|
|
||||||
assertTrue(user == null);
|
assertTrue(user == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,8 +120,7 @@ public class UserAttributeEditorTests extends TestCase {
|
||||||
UserAttributeEditor editor = new UserAttributeEditor();
|
UserAttributeEditor editor = new UserAttributeEditor();
|
||||||
editor.setAsText(null);
|
editor.setAsText(null);
|
||||||
|
|
||||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
UserAttribute user = (UserAttribute) editor.getValue();
|
||||||
.getValue();
|
|
||||||
assertTrue(user == null);
|
assertTrue(user == null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2485,7 +2485,7 @@ public boolean supports(Class clazz);</programlisting></para>
|
||||||
<para><programlisting>base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
|
<para><programlisting>base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
|
||||||
|
|
||||||
expirationTime: The date and time when the nonce expires, expressed in milliseconds
|
expirationTime: The date and time when the nonce expires, expressed in milliseconds
|
||||||
key: A private key to prevent modification of the nounce token
|
key: A private key to prevent modification of the nonce token
|
||||||
</programlisting></para>
|
</programlisting></para>
|
||||||
|
|
||||||
<para>The <literal>DigestProcessingFilterEntryPoint</literal> has a
|
<para>The <literal>DigestProcessingFilterEntryPoint</literal> has a
|
||||||
|
@ -2548,7 +2548,7 @@ key: A private key to prevent modification of the nounce token
|
||||||
<para>The configured <literal>AuthenticationDao</literal> is needed
|
<para>The configured <literal>AuthenticationDao</literal> is needed
|
||||||
because <literal>DigestProcessingFilter</literal> must have direct
|
because <literal>DigestProcessingFilter</literal> must have direct
|
||||||
access to the clear text password of a user. Digest Authentication
|
access to the clear text password of a user. Digest Authentication
|
||||||
will NOT work if you are using encoded passwords ni your DAO. The DAO
|
will NOT work if you are using encoded passwords in your DAO. The DAO
|
||||||
collaborator, along with the <literal>UserCache</literal>, are
|
collaborator, along with the <literal>UserCache</literal>, are
|
||||||
typically shared directly with a
|
typically shared directly with a
|
||||||
<literal>DaoAuthenticationProvider</literal>. The
|
<literal>DaoAuthenticationProvider</literal>. The
|
||||||
|
@ -2556,7 +2556,7 @@ key: A private key to prevent modification of the nounce token
|
||||||
<literal>DigestProcessingFilterEntryPoint</literal>, so that
|
<literal>DigestProcessingFilterEntryPoint</literal>, so that
|
||||||
<literal>DigestProcessingFilter</literal> can obtain the correct
|
<literal>DigestProcessingFilter</literal> can obtain the correct
|
||||||
<literal>realmName</literal> and <literal>key</literal> for digest
|
<literal>realmName</literal> and <literal>key</literal> for digest
|
||||||
calculations. </para>
|
calculations.</para>
|
||||||
|
|
||||||
<para>Like <literal>BasicAuthenticationFilter</literal>, if
|
<para>Like <literal>BasicAuthenticationFilter</literal>, if
|
||||||
authentication is successful an <literal>Authentication</literal>
|
authentication is successful an <literal>Authentication</literal>
|
||||||
|
@ -2580,6 +2580,95 @@ key: A private key to prevent modification of the nounce token
|
||||||
does comply with the minimum standards of this RFC.</para>
|
does comply with the minimum standards of this RFC.</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="security-ui-anonymous">
|
||||||
|
<title>Anonymous Authentication</title>
|
||||||
|
|
||||||
|
<para>Particularly in the case of web request URI security, sometimes
|
||||||
|
it is more convenient to assign configuration attributes against every
|
||||||
|
possible secure object invocation. Put differently, sometimes it is
|
||||||
|
nice to say <literal>ROLE_SOMETHING</literal> is required by default
|
||||||
|
and only allow certain exceptions to this rule, such as for login,
|
||||||
|
logout and home pages of an application. There are also other
|
||||||
|
situations where anonymous authentication would be desired, such as
|
||||||
|
when an auditing interceptor queries the
|
||||||
|
<literal>ContextHolder</literal> to identify which principal was
|
||||||
|
responsible for a given operation. Such classes can be authored with
|
||||||
|
more robustness if they know the <literal>ContextHolder</literal>
|
||||||
|
always contains an <literal>Authentication</literal> object, and never
|
||||||
|
<literal>null</literal>.</para>
|
||||||
|
|
||||||
|
<para>Acegi Security provides three classes that together provide an
|
||||||
|
anoymous authentication feature.
|
||||||
|
<literal>AnonymousAuthenticationToken</literal> is an implementation
|
||||||
|
of <literal>Authentication</literal>, and stores the
|
||||||
|
<literal>GrantedAuthority</literal>[]s which apply to the anonymous
|
||||||
|
principal. There is a corresponding
|
||||||
|
<literal>AnonymousAuthenticationProvider</literal>, which is chained
|
||||||
|
into the <literal>ProviderManager</literal> so that
|
||||||
|
<literal>AnonymousAuthenticationTokens</literal> are accepted.
|
||||||
|
Finally, there is an AnonymousProcessingFilter, which is chained after
|
||||||
|
the normal authentication mechanisms and automatically add an
|
||||||
|
<literal>AnonymousAuthenticationToken</literal> to the
|
||||||
|
<literal>ContextHolder</literal> if there is no existing
|
||||||
|
<literal>Authentication</literal> held there. The definition of the
|
||||||
|
filter and authentication provider appears as follows:</para>
|
||||||
|
|
||||||
|
<para><programlisting><bean id="anonymousProcessingFilter" class="net.sf.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
|
||||||
|
<property name="key"><value>foobar</value></property>
|
||||||
|
<property name="userAttribute"><value>anonymousUser,ROLE_ANONYMOUS</value></property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="anonymousAuthenticationProvider" class="net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
|
||||||
|
<property name="key"><value>foobar</value></property>
|
||||||
|
</bean></programlisting></para>
|
||||||
|
|
||||||
|
<para>The <literal>key</literal> is shared between the filter and
|
||||||
|
authentication provider, so that tokens created by the former are
|
||||||
|
accepted by the latter. The <literal>userAttribute</literal> is
|
||||||
|
expressed in the form of
|
||||||
|
<literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>.
|
||||||
|
This is the same syntax as used after the equals sign for
|
||||||
|
<literal>InMemoryDaoImpl</literal>'s <literal>userMap</literal>
|
||||||
|
property.</para>
|
||||||
|
|
||||||
|
<para>As explained earlier, the benefit of anonymous authentication is
|
||||||
|
that all URI patterns can have security applied to them. For
|
||||||
|
example:</para>
|
||||||
|
|
||||||
|
<para><programlisting><bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
|
||||||
|
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
|
||||||
|
<property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>
|
||||||
|
<property name="objectDefinitionSource">
|
||||||
|
<value>
|
||||||
|
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
||||||
|
PATTERN_TYPE_APACHE_ANT
|
||||||
|
/index.jsp=ROLE_ANONYMOUS,ROLE_USER
|
||||||
|
/hello.htm=ROLE_ANONYMOUS,ROLE_USER
|
||||||
|
/logoff.jsp=ROLE_ANONYMOUS,ROLE_USER
|
||||||
|
/acegilogin.jsp=ROLE_ANONYMOUS,ROLE_USER
|
||||||
|
/**=ROLE_USER
|
||||||
|
</value>
|
||||||
|
</property>
|
||||||
|
</bean></programlisting>Rounding out the anonymous authentication
|
||||||
|
discussion is the <literal>AuthenticationTrustResolver</literal>
|
||||||
|
interface, with its corresponding
|
||||||
|
<literal>AuthenticationTrustResolverImpl</literal> implementation.
|
||||||
|
This interface provides an
|
||||||
|
<literal>isAnonymous(Authentication)</literal> method, which allows
|
||||||
|
interested classes to take into account this special type of
|
||||||
|
authentication status. The
|
||||||
|
<literal>SecurityEnforcementFilter</literal> uses this interface in
|
||||||
|
processing <literal>AccessDeniedException</literal>s. If an
|
||||||
|
<literal>AccessDeniedException</literal> is thrown, and the
|
||||||
|
authentication is of an anonymous type, instead of throwing a 403
|
||||||
|
(forbidden) response, the filter will instead commence the
|
||||||
|
<literal>AuthenticationEntryPoint</literal> so the principal can
|
||||||
|
authenticate properly. This is a necessary distinction, otherwise
|
||||||
|
principals would always be deemed "authenticated" and never be given
|
||||||
|
an opportunity to login via form, basic, digest or some other normal
|
||||||
|
authentication mechanism.</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="security-ui-well-known">
|
<sect2 id="security-ui-well-known">
|
||||||
<title>Well-Known Locations</title>
|
<title>Well-Known Locations</title>
|
||||||
|
|
||||||
|
@ -4393,6 +4482,13 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1);</programlisting></para>
|
||||||
container</para>
|
container</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><literal>AnonymousProcessingFilter</literal>, so that if no
|
||||||
|
earlier authentication processing mechanism updated the
|
||||||
|
<literal>ContextHolder</literal>, an anonymous
|
||||||
|
<literal>Authentication</literal> object will be put there</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para><literal>SecurityEnforcementFilter</literal>, to protect web
|
<para><literal>SecurityEnforcementFilter</literal>, to protect web
|
||||||
URIs and catch any Acegi Security exceptions so that an
|
URIs and catch any Acegi Security exceptions so that an
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<value>
|
<value>
|
||||||
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
||||||
PATTERN_TYPE_APACHE_ANT
|
PATTERN_TYPE_APACHE_ANT
|
||||||
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,securityEnforcementFilter
|
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter
|
||||||
</value>
|
</value>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
@ -32,6 +32,7 @@
|
||||||
<property name="providers">
|
<property name="providers">
|
||||||
<list>
|
<list>
|
||||||
<ref local="daoAuthenticationProvider"/>
|
<ref local="daoAuthenticationProvider"/>
|
||||||
|
<ref local="anonymousAuthenticationProvider"/>
|
||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
@ -75,6 +76,15 @@
|
||||||
<property name="realmName"><value>Contacts Realm</value></property>
|
<property name="realmName"><value>Contacts Realm</value></property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="anonymousProcessingFilter" class="net.sf.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
|
||||||
|
<property name="key"><value>foobar</value></property>
|
||||||
|
<property name="userAttribute"><value>anonymousUser,ROLE_ANONYMOUS</value></property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="anonymousAuthenticationProvider" class="net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
|
||||||
|
<property name="key"><value>foobar</value></property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<bean id="httpSessionContextIntegrationFilter" class="net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter">
|
<bean id="httpSessionContextIntegrationFilter" class="net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter">
|
||||||
<property name="context"><value>net.sf.acegisecurity.context.security.SecureContextImpl</value></property>
|
<property name="context"><value>net.sf.acegisecurity.context.security.SecureContextImpl</value></property>
|
||||||
</bean>
|
</bean>
|
||||||
|
@ -146,33 +156,14 @@
|
||||||
<property name="objectDefinitionSource">
|
<property name="objectDefinitionSource">
|
||||||
<value>
|
<value>
|
||||||
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
||||||
\A/secure/super.*\Z=ROLE_WE_DONT_HAVE
|
PATTERN_TYPE_APACHE_ANT
|
||||||
\A/secure/.*\Z=ROLE_SUPERVISOR,ROLE_USER
|
/index.jsp=ROLE_ANONYMOUS,ROLE_USER
|
||||||
|
/hello.htm=ROLE_ANONYMOUS,ROLE_USER
|
||||||
|
/logoff.jsp=ROLE_ANONYMOUS,ROLE_USER
|
||||||
|
/acegilogin.jsp=ROLE_ANONYMOUS,ROLE_USER
|
||||||
|
/**=ROLE_USER
|
||||||
</value>
|
</value>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<!-- BASIC Regular Expression Syntax (for beginners):
|
|
||||||
|
|
||||||
\A means the start of the string (ie the beginning of the URL)
|
|
||||||
\Z means the end of the string (ie the end of the URL)
|
|
||||||
. means any single character
|
|
||||||
* means null or any number of repetitions of the last expression (so .* means zero or more characters)
|
|
||||||
|
|
||||||
Some examples:
|
|
||||||
|
|
||||||
Expression: \A/my/directory/.*\Z
|
|
||||||
Would match: /my/directory/
|
|
||||||
/my/directory/hello.html
|
|
||||||
|
|
||||||
Expression: \A/.*\Z
|
|
||||||
Would match: /hello.html
|
|
||||||
/
|
|
||||||
|
|
||||||
Expression: \A/.*/secret.html\Z
|
|
||||||
Would match: /some/directory/secret.html
|
|
||||||
/another/secret.html
|
|
||||||
Not match: /anothersecret.html (missing required /)
|
|
||||||
-->
|
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
|
Loading…
Reference in New Issue