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");
|
||||
* 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
|
||||
* 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,
|
||||
ConfigAttributeDefinition config) throws AccessDeniedException;
|
||||
ConfigAttributeDefinition config)
|
||||
throws AccessDeniedException, InsufficientAuthenticationException;
|
||||
|
||||
/**
|
||||
* 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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,9 +16,8 @@
|
|||
package net.sf.acegisecurity;
|
||||
|
||||
/**
|
||||
* Abstract superclass for all exceptions related to the {@link
|
||||
* AuthenticationManager} being unable to authenticate an {@link
|
||||
* Authentication} object.
|
||||
* Abstract superclass for all exceptions related an {@link Authentication}
|
||||
* object being invalid for whatever reason.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
|
@ -57,11 +56,11 @@ public abstract class AuthenticationException extends AcegiSecurityException {
|
|||
|
||||
//~ Methods ================================================================
|
||||
|
||||
void setAuthentication(Authentication authentication) {
|
||||
this.authentication = authentication;
|
||||
}
|
||||
|
||||
public Authentication getAuthentication() {
|
||||
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");
|
||||
* 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.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.util.PortResolver;
|
||||
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.util.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
@ -54,10 +59,13 @@ import javax.servlet.http.HttpServletResponse;
|
|||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If an {@link AccessDeniedException} is detected, 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
|
||||
* If an {@link AccessDeniedException} is detected, the filter will determine
|
||||
* whether or not the user is an anonymous user. If they are an anonymous
|
||||
* user, the <code>authenticationEntryPoint</code> will be launched. If they
|
||||
* 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
|
||||
* trace etc). Again, this allows common access denied handling irrespective
|
||||
* of the originating security interceptor.
|
||||
|
@ -104,6 +112,7 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
|
|||
//~ Instance fields ========================================================
|
||||
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
||||
private FilterSecurityInterceptor filterSecurityInterceptor;
|
||||
private PortResolver portResolver = new PortResolverImpl();
|
||||
|
||||
|
@ -118,6 +127,15 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
|
|||
return authenticationEntryPoint;
|
||||
}
|
||||
|
||||
public void setAuthenticationTrustResolver(
|
||||
AuthenticationTrustResolver authenticationTrustResolver) {
|
||||
this.authenticationTrustResolver = authenticationTrustResolver;
|
||||
}
|
||||
|
||||
public AuthenticationTrustResolver getAuthenticationTrustResolver() {
|
||||
return authenticationTrustResolver;
|
||||
}
|
||||
|
||||
public void setFilterSecurityInterceptor(
|
||||
FilterSecurityInterceptor filterSecurityInterceptor) {
|
||||
this.filterSecurityInterceptor = filterSecurityInterceptor;
|
||||
|
@ -136,19 +154,13 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
|
|||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (authenticationEntryPoint == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"authenticationEntryPoint must be specified");
|
||||
}
|
||||
|
||||
if (filterSecurityInterceptor == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"filterSecurityInterceptor must be specified");
|
||||
}
|
||||
|
||||
if (portResolver == null) {
|
||||
throw new IllegalArgumentException("portResolver must be specified");
|
||||
}
|
||||
Assert.notNull(authenticationEntryPoint,
|
||||
"authenticationEntryPoint must be specified");
|
||||
Assert.notNull(filterSecurityInterceptor,
|
||||
"filterSecurityInterceptor must be specified");
|
||||
Assert.notNull(portResolver, "portResolver must be specified");
|
||||
Assert.notNull(authenticationTrustResolver,
|
||||
"authenticationTrustResolver must be specified");
|
||||
}
|
||||
|
||||
public void destroy() {}
|
||||
|
@ -172,43 +184,29 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
|
|||
logger.debug("Chain processed normally");
|
||||
}
|
||||
} 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()) {
|
||||
logger.debug(
|
||||
"Authentication failed - adding target URL to Session: "
|
||||
+ targetUrl, authentication);
|
||||
logger.debug("Authentication exception occurred; redirecting to authentication entry point",
|
||||
authentication);
|
||||
}
|
||||
|
||||
((HttpServletRequest) request).getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY,
|
||||
targetUrl);
|
||||
authenticationEntryPoint.commence(request, response, authentication);
|
||||
sendStartAuthentication(fi, authentication);
|
||||
} catch (AccessDeniedException accessDenied) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
"Access is denied - sending back forbidden response");
|
||||
}
|
||||
if (authenticationTrustResolver.isAnonymous(
|
||||
SecureContextUtils.getSecureContext().getAuthentication())) {
|
||||
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,
|
||||
accessDenied);
|
||||
sendAccessDeniedError(request, response, accessDenied);
|
||||
sendStartAuthentication(fi, null);
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Access is denied (user is not anonymous); sending back forbidden response",
|
||||
accessDenied);
|
||||
}
|
||||
|
||||
sendAccessDeniedError(fi, accessDenied);
|
||||
}
|
||||
} catch (Throwable otherException) {
|
||||
throw new ServletException(otherException);
|
||||
}
|
||||
|
@ -216,19 +214,43 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
|
|||
|
||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||
|
||||
/**
|
||||
* Allows subclasses to override if required
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param accessDenied
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void sendAccessDeniedError(ServletRequest request,
|
||||
ServletResponse response, AccessDeniedException accessDenied)
|
||||
throws IOException {
|
||||
((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN,
|
||||
protected void sendAccessDeniedError(FilterInvocation fi,
|
||||
AccessDeniedException accessDenied)
|
||||
throws ServletException, IOException {
|
||||
((HttpServletRequest) fi.getRequest()).getSession().setAttribute(ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY,
|
||||
accessDenied);
|
||||
((HttpServletResponse) fi.getResponse()).sendError(HttpServletResponse.SC_FORBIDDEN,
|
||||
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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -29,7 +29,7 @@ import java.util.Vector;
|
|||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class UserAttributeDefinition {
|
||||
public class UserAttribute {
|
||||
//~ Instance fields ========================================================
|
||||
|
||||
private List authorities = new Vector();
|
||||
|
@ -38,7 +38,7 @@ public class UserAttributeDefinition {
|
|||
|
||||
//~ Constructors ===========================================================
|
||||
|
||||
public UserAttributeDefinition() {
|
||||
public UserAttribute() {
|
||||
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");
|
||||
* 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
|
||||
* separated list of values.
|
||||
* Property editor that creates a {@link UserAttribute} from a comma separated
|
||||
* list of values.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
|
@ -37,7 +37,7 @@ public class UserAttributeEditor extends PropertyEditorSupport {
|
|||
setValue(null);
|
||||
} else {
|
||||
String[] tokens = StringUtils.commaDelimitedListToStringArray(s);
|
||||
UserAttributeDefinition userAttrib = new UserAttributeDefinition();
|
||||
UserAttribute userAttrib = new UserAttribute();
|
||||
|
||||
for (int i = 0; i < tokens.length; 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");
|
||||
* 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
|
||||
configAttribEd.setAsText(value);
|
||||
|
||||
UserAttributeDefinition attr = (UserAttributeDefinition) configAttribEd
|
||||
.getValue();
|
||||
UserAttribute attr = (UserAttribute) configAttribEd.getValue();
|
||||
|
||||
// Make a user object, assuming the properties were properly provided
|
||||
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");
|
||||
* 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.BadCredentialsException;
|
||||
import net.sf.acegisecurity.GrantedAuthority;
|
||||
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||
import net.sf.acegisecurity.MockAuthenticationEntryPoint;
|
||||
import net.sf.acegisecurity.MockHttpServletRequest;
|
||||
import net.sf.acegisecurity.MockHttpServletResponse;
|
||||
import net.sf.acegisecurity.MockHttpSession;
|
||||
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 java.io.IOException;
|
||||
|
@ -62,8 +68,47 @@ public class SecurityEnforcementFilterTests extends TestCase {
|
|||
junit.textui.TestRunner.run(SecurityEnforcementFilterTests.class);
|
||||
}
|
||||
|
||||
public void testAccessDeniedWhenAccessDeniedException()
|
||||
throws Exception {
|
||||
public void testAccessDeniedWhenAnonymous() 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
|
||||
HttpSession session = new MockHttpSession();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(null,
|
||||
|
@ -77,6 +122,11 @@ public class SecurityEnforcementFilterTests extends TestCase {
|
|||
MockFilterSecurityInterceptor interceptor = new MockFilterSecurityInterceptor(true,
|
||||
false);
|
||||
|
||||
// Setup ContextHolder, as filter needs to check if user is anonymous
|
||||
SecureContext sc = new SecureContextImpl();
|
||||
sc.setAuthentication(null);
|
||||
ContextHolder.setContext(sc);
|
||||
|
||||
// Test
|
||||
SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
|
||||
filter.setFilterSecurityInterceptor(interceptor);
|
||||
|
@ -281,6 +331,11 @@ public class SecurityEnforcementFilterTests extends TestCase {
|
|||
assertTrue(true);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
ContextHolder.setContext(null);
|
||||
}
|
||||
|
||||
//~ Inner Classes ==========================================================
|
||||
|
||||
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");
|
||||
* 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
|
||||
* UserAttributeDefinition}.
|
||||
* Tests {@link UserAttributeEditor} and associated {@link UserAttribute}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
|
@ -50,8 +49,7 @@ public class UserAttributeEditorTests extends TestCase {
|
|||
UserAttributeEditor editor = new UserAttributeEditor();
|
||||
editor.setAsText("password,ROLE_ONE,ROLE_TWO");
|
||||
|
||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
||||
.getValue();
|
||||
UserAttribute user = (UserAttribute) editor.getValue();
|
||||
assertTrue(user.isValid());
|
||||
assertTrue(user.isEnabled()); // default
|
||||
assertEquals("password", user.getPassword());
|
||||
|
@ -64,8 +62,7 @@ public class UserAttributeEditorTests extends TestCase {
|
|||
UserAttributeEditor editor = new UserAttributeEditor();
|
||||
editor.setAsText("password,disabled,ROLE_ONE,ROLE_TWO");
|
||||
|
||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
||||
.getValue();
|
||||
UserAttribute user = (UserAttribute) editor.getValue();
|
||||
assertTrue(user.isValid());
|
||||
assertTrue(!user.isEnabled());
|
||||
assertEquals("password", user.getPassword());
|
||||
|
@ -78,8 +75,7 @@ public class UserAttributeEditorTests extends TestCase {
|
|||
UserAttributeEditor editor = new UserAttributeEditor();
|
||||
editor.setAsText("");
|
||||
|
||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
||||
.getValue();
|
||||
UserAttribute user = (UserAttribute) editor.getValue();
|
||||
assertTrue(user == null);
|
||||
}
|
||||
|
||||
|
@ -87,8 +83,7 @@ public class UserAttributeEditorTests extends TestCase {
|
|||
UserAttributeEditor editor = new UserAttributeEditor();
|
||||
editor.setAsText("password,ROLE_ONE,enabled,ROLE_TWO");
|
||||
|
||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
||||
.getValue();
|
||||
UserAttribute user = (UserAttribute) editor.getValue();
|
||||
assertTrue(user.isValid());
|
||||
assertTrue(user.isEnabled());
|
||||
assertEquals("password", user.getPassword());
|
||||
|
@ -101,8 +96,7 @@ public class UserAttributeEditorTests extends TestCase {
|
|||
UserAttributeEditor editor = new UserAttributeEditor();
|
||||
editor.setAsText("MALFORMED_STRING");
|
||||
|
||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
||||
.getValue();
|
||||
UserAttribute user = (UserAttribute) editor.getValue();
|
||||
assertTrue(user == null);
|
||||
}
|
||||
|
||||
|
@ -110,8 +104,7 @@ public class UserAttributeEditorTests extends TestCase {
|
|||
UserAttributeEditor editor = new UserAttributeEditor();
|
||||
editor.setAsText("disabled");
|
||||
|
||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
||||
.getValue();
|
||||
UserAttribute user = (UserAttribute) editor.getValue();
|
||||
assertTrue(user == null);
|
||||
}
|
||||
|
||||
|
@ -119,8 +112,7 @@ public class UserAttributeEditorTests extends TestCase {
|
|||
UserAttributeEditor editor = new UserAttributeEditor();
|
||||
editor.setAsText("password,enabled");
|
||||
|
||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
||||
.getValue();
|
||||
UserAttribute user = (UserAttribute) editor.getValue();
|
||||
assertTrue(user == null);
|
||||
}
|
||||
|
||||
|
@ -128,8 +120,7 @@ public class UserAttributeEditorTests extends TestCase {
|
|||
UserAttributeEditor editor = new UserAttributeEditor();
|
||||
editor.setAsText(null);
|
||||
|
||||
UserAttributeDefinition user = (UserAttributeDefinition) editor
|
||||
.getValue();
|
||||
UserAttribute user = (UserAttribute) editor.getValue();
|
||||
assertTrue(user == null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2485,7 +2485,7 @@ public boolean supports(Class clazz);</programlisting></para>
|
|||
<para><programlisting>base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
|
||||
|
||||
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>
|
||||
|
||||
<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
|
||||
because <literal>DigestProcessingFilter</literal> must have direct
|
||||
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
|
||||
typically shared directly with a
|
||||
<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>DigestProcessingFilter</literal> can obtain the correct
|
||||
<literal>realmName</literal> and <literal>key</literal> for digest
|
||||
calculations. </para>
|
||||
calculations.</para>
|
||||
|
||||
<para>Like <literal>BasicAuthenticationFilter</literal>, if
|
||||
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>
|
||||
</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">
|
||||
<title>Well-Known Locations</title>
|
||||
|
||||
|
@ -4393,6 +4482,13 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1);</programlisting></para>
|
|||
container</para>
|
||||
</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>
|
||||
<para><literal>SecurityEnforcementFilter</literal>, to protect web
|
||||
URIs and catch any Acegi Security exceptions so that an
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<value>
|
||||
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
||||
PATTERN_TYPE_APACHE_ANT
|
||||
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,securityEnforcementFilter
|
||||
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
@ -32,6 +32,7 @@
|
|||
<property name="providers">
|
||||
<list>
|
||||
<ref local="daoAuthenticationProvider"/>
|
||||
<ref local="anonymousAuthenticationProvider"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
@ -75,6 +76,15 @@
|
|||
<property name="realmName"><value>Contacts Realm</value></property>
|
||||
</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">
|
||||
<property name="context"><value>net.sf.acegisecurity.context.security.SecureContextImpl</value></property>
|
||||
</bean>
|
||||
|
@ -146,33 +156,14 @@
|
|||
<property name="objectDefinitionSource">
|
||||
<value>
|
||||
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
||||
\A/secure/super.*\Z=ROLE_WE_DONT_HAVE
|
||||
\A/secure/.*\Z=ROLE_SUPERVISOR,ROLE_USER
|
||||
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>
|
||||
|
||||
<!-- 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>
|
||||
|
|
Loading…
Reference in New Issue