SEC-271: work on security:autoconfig
This commit is contained in:
parent
6e82a9bdfc
commit
b2c30277f4
|
@ -15,140 +15,192 @@
|
|||
|
||||
package org.acegisecurity.providers.dao;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.acegisecurity.AuthenticationException;
|
||||
import org.acegisecurity.AuthenticationServiceException;
|
||||
import org.acegisecurity.BadCredentialsException;
|
||||
|
||||
import org.acegisecurity.providers.AuthenticationProvider;
|
||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.acegisecurity.providers.encoding.PasswordEncoder;
|
||||
import org.acegisecurity.providers.encoding.PlaintextPasswordEncoder;
|
||||
|
||||
import org.acegisecurity.userdetails.UserDetails;
|
||||
import org.acegisecurity.userdetails.UserDetailsService;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationProvider} implementation that retrieves user details from an {@link UserDetailsService}.
|
||||
*
|
||||
* An {@link AuthenticationProvider} implementation that retrieves user details
|
||||
* from an {@link UserDetailsService}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @version $Id: DaoAuthenticationProvider.java 1857 2007-05-24 00:47:12Z
|
||||
* benalex $
|
||||
*/
|
||||
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider implements Ordered {
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider implements
|
||||
ApplicationContextAware, Ordered {
|
||||
|
||||
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
|
||||
private SaltSource saltSource;
|
||||
private UserDetailsService userDetailsService;
|
||||
private boolean includeDetailsObject = true;
|
||||
private int order = -1; // default: same as non-Ordered
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
|
||||
|
||||
protected void additionalAuthenticationChecks(UserDetails userDetails,
|
||||
UsernamePasswordAuthenticationToken authentication)
|
||||
throws AuthenticationException {
|
||||
Object salt = null;
|
||||
private SaltSource saltSource;
|
||||
|
||||
if (this.saltSource != null) {
|
||||
salt = this.saltSource.getSalt(userDetails);
|
||||
}
|
||||
|
||||
if (authentication.getCredentials() == null) {
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
||||
includeDetailsObject ? userDetails : null);
|
||||
}
|
||||
|
||||
String presentedPassword = authentication.getCredentials() == null ? "" : authentication.getCredentials().toString();
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
if (!passwordEncoder.isPasswordValid(
|
||||
userDetails.getPassword(), presentedPassword, salt)) {
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
||||
includeDetailsObject ? userDetails : null);
|
||||
}
|
||||
}
|
||||
private boolean includeDetailsObject = true;
|
||||
|
||||
protected void doAfterPropertiesSet() throws Exception {
|
||||
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
|
||||
}
|
||||
private int DEFAULT_RDER = Integer.MAX_VALUE; // default: same as
|
||||
|
||||
public PasswordEncoder getPasswordEncoder() {
|
||||
return passwordEncoder;
|
||||
}
|
||||
// non-Ordered
|
||||
|
||||
public SaltSource getSaltSource() {
|
||||
return saltSource;
|
||||
}
|
||||
private int order = DEFAULT_RDER;
|
||||
|
||||
public UserDetailsService getUserDetailsService() {
|
||||
return userDetailsService;
|
||||
}
|
||||
private boolean isSetUserDetailsServiceInvoked;
|
||||
|
||||
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
|
||||
throws AuthenticationException {
|
||||
UserDetails loadedUser;
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
try {
|
||||
loadedUser = this.getUserDetailsService().loadUserByUsername(username);
|
||||
} catch (DataAccessException repositoryProblem) {
|
||||
throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
|
||||
}
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
if (loadedUser == null) {
|
||||
throw new AuthenticationServiceException(
|
||||
"UserDetailsService returned null, which is an interface contract violation");
|
||||
}
|
||||
return loadedUser;
|
||||
}
|
||||
protected void additionalAuthenticationChecks(UserDetails userDetails,
|
||||
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
|
||||
Object salt = null;
|
||||
|
||||
/**
|
||||
* Sets the PasswordEncoder instance to be used to encode and validate passwords. If not set, {@link
|
||||
* PlaintextPasswordEncoder} will be used by default.
|
||||
*
|
||||
* @param passwordEncoder The passwordEncoder to use
|
||||
*/
|
||||
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
if (this.saltSource != null) {
|
||||
salt = this.saltSource.getSalt(userDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* The source of salts to use when decoding passwords. <code>null</code> is a valid value, meaning the
|
||||
* <code>DaoAuthenticationProvider</code> will present <code>null</code> to the relevant
|
||||
* <code>PasswordEncoder</code>.
|
||||
*
|
||||
* @param saltSource to use when attempting to decode passwords via the <code>PasswordEncoder</code>
|
||||
*/
|
||||
public void setSaltSource(SaltSource saltSource) {
|
||||
this.saltSource = saltSource;
|
||||
}
|
||||
if (authentication.getCredentials() == null) {
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
||||
includeDetailsObject ? userDetails : null);
|
||||
}
|
||||
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
String presentedPassword = authentication.getCredentials() == null ? "" : authentication.getCredentials()
|
||||
.toString();
|
||||
|
||||
public boolean isIncludeDetailsObject() {
|
||||
return includeDetailsObject;
|
||||
}
|
||||
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
||||
includeDetailsObject ? userDetails : null);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIncludeDetailsObject(boolean includeDetailsObject) {
|
||||
this.includeDetailsObject = includeDetailsObject;
|
||||
}
|
||||
protected void doAfterPropertiesSet() throws Exception {
|
||||
if (!isSetUserDetailsServiceInvoked) {
|
||||
autoDetectAnyUserDetailsServiceAndUseIt(this.applicationContext);
|
||||
}
|
||||
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
|
||||
}
|
||||
|
||||
/**
|
||||
* Introspects the <code>Applicationcontext</code> for the single instance
|
||||
* of {@link AccessDeniedHandler}. If found invoke
|
||||
* setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) method by
|
||||
* providing the found instance of accessDeniedHandler as a method
|
||||
* parameter. If more than one instance of <code>AccessDeniedHandler</code>
|
||||
* is found, the method throws <code>IllegalStateException</code>.
|
||||
*
|
||||
* @param applicationContext to locate the instance
|
||||
*/
|
||||
private void autoDetectAnyUserDetailsServiceAndUseIt(ApplicationContext applicationContext) {
|
||||
if (applicationContext != null) {
|
||||
Map map = applicationContext.getBeansOfType(UserDetailsService.class);
|
||||
|
||||
if (map.size() > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"More than one UserDetailsService beans detected please refer to the one using "
|
||||
+ " [ principalRepositoryBeanRef ] " + "attribute");
|
||||
}
|
||||
else if (map.size() == 1) {
|
||||
setUserDetailsService((UserDetailsService) map.values().iterator().next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PasswordEncoder getPasswordEncoder() {
|
||||
return passwordEncoder;
|
||||
}
|
||||
|
||||
public SaltSource getSaltSource() {
|
||||
return saltSource;
|
||||
}
|
||||
|
||||
public UserDetailsService getUserDetailsService() {
|
||||
return userDetailsService;
|
||||
}
|
||||
|
||||
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
|
||||
throws AuthenticationException {
|
||||
UserDetails loadedUser;
|
||||
|
||||
try {
|
||||
loadedUser = this.getUserDetailsService().loadUserByUsername(username);
|
||||
}
|
||||
catch (DataAccessException repositoryProblem) {
|
||||
throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
|
||||
}
|
||||
|
||||
if (loadedUser == null) {
|
||||
throw new AuthenticationServiceException(
|
||||
"UserDetailsService returned null, which is an interface contract violation");
|
||||
}
|
||||
return loadedUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the PasswordEncoder instance to be used to encode and validate
|
||||
* passwords. If not set, {@link PlaintextPasswordEncoder} will be used by
|
||||
* default.
|
||||
*
|
||||
* @param passwordEncoder The passwordEncoder to use
|
||||
*/
|
||||
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* The source of salts to use when decoding passwords. <code>null</code>
|
||||
* is a valid value, meaning the <code>DaoAuthenticationProvider</code>
|
||||
* will present <code>null</code> to the relevant
|
||||
* <code>PasswordEncoder</code>.
|
||||
*
|
||||
* @param saltSource to use when attempting to decode passwords via the
|
||||
* <code>PasswordEncoder</code>
|
||||
*/
|
||||
public void setSaltSource(SaltSource saltSource) {
|
||||
this.saltSource = saltSource;
|
||||
}
|
||||
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
isSetUserDetailsServiceInvoked = true;
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
public boolean isIncludeDetailsObject() {
|
||||
return includeDetailsObject;
|
||||
}
|
||||
|
||||
public void setIncludeDetailsObject(boolean includeDetailsObject) {
|
||||
this.includeDetailsObject = includeDetailsObject;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order ;
|
||||
return order;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,12 +27,16 @@ import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEv
|
|||
import org.acegisecurity.ui.rememberme.NullRememberMeServices;
|
||||
import org.acegisecurity.ui.rememberme.RememberMeServices;
|
||||
import org.acegisecurity.ui.savedrequest.SavedRequest;
|
||||
import org.acegisecurity.userdetails.UserDetailsService;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.MessageSource;
|
||||
|
@ -43,6 +47,7 @@ import org.springframework.util.Assert;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
@ -54,424 +59,535 @@ import javax.servlet.ServletResponse;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract processor of browser-based HTTP-based authentication requests.<p>This filter is responsible for
|
||||
* processing authentication requests. If authentication is successful, the resulting {@link Authentication} object
|
||||
* will be placed into the <code>SecurityContext</code>, which is guaranteed to have already been created by an
|
||||
* earlier filter.</p>
|
||||
* <p>If authentication fails, the <code>AuthenticationException</code> will be placed into the
|
||||
* <code>HttpSession</code> with the attribute defined by {@link #ACEGI_SECURITY_LAST_EXCEPTION_KEY}.</p>
|
||||
* <p>To use this filter, it is necessary to specify the following properties:</p>
|
||||
* <ul>
|
||||
* <li><code>defaultTargetUrl</code> indicates the URL that should be used for redirection if the
|
||||
* <code>HttpSession</code> attribute named {@link #ACEGI_SAVED_REQUEST_KEY} does not indicate the target URL once
|
||||
* authentication is completed successfully. eg: <code>/</code>. The <code>defaultTargetUrl</code> will be treated
|
||||
* as relative to the web-app's context path, and should include the leading <code>/</code>. Alternatively,
|
||||
* inclusion of a scheme name (eg http:// or https://) as the prefix will denote a fully-qualified URL and this is
|
||||
* also supported.</li>
|
||||
* <li><code>authenticationFailureUrl</code> indicates the URL that should be used for redirection if the
|
||||
* authentication request fails. eg: <code>/login.jsp?login_error=1</code>.</li>
|
||||
* <li><code>filterProcessesUrl</code> indicates the URL that this filter will respond to. This parameter
|
||||
* varies by subclass.</li>
|
||||
* <li><code>alwaysUseDefaultTargetUrl</code> causes successful authentication to always redirect to the
|
||||
* <code>defaultTargetUrl</code>, even if the <code>HttpSession</code> attribute named {@link
|
||||
* #ACEGI_SAVED_REQUEST_KEY} defines the intended target URL.</li>
|
||||
* </ul>
|
||||
* <p>To configure this filter to redirect to specific pages as the result of specific {@link
|
||||
* AuthenticationException}s you can do the following. Configure the <code>exceptionMappings</code> property in your
|
||||
* application xml. This property is a java.util.Properties object that maps a fully-qualified exception class name to
|
||||
* a redirection url target.
|
||||
* For example:
|
||||
* Abstract processor of browser-based HTTP-based authentication requests.
|
||||
* <p>
|
||||
* This filter is responsible for processing authentication requests. If
|
||||
* authentication is successful, the resulting {@link Authentication} object
|
||||
* will be placed into the <code>SecurityContext</code>, which is guaranteed
|
||||
* to have already been created by an earlier filter.
|
||||
* </p>
|
||||
* <p>
|
||||
* If authentication fails, the <code>AuthenticationException</code> will be
|
||||
* placed into the <code>HttpSession</code> with the attribute defined by
|
||||
* {@link #ACEGI_SECURITY_LAST_EXCEPTION_KEY}.
|
||||
* </p>
|
||||
* <p>
|
||||
* To use this filter, it is necessary to specify the following properties:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><code>defaultTargetUrl</code> indicates the URL that should be used
|
||||
* for redirection if the <code>HttpSession</code> attribute named
|
||||
* {@link #ACEGI_SAVED_REQUEST_KEY} does not indicate the target URL once
|
||||
* authentication is completed successfully. eg: <code>/</code>. The
|
||||
* <code>defaultTargetUrl</code> will be treated as relative to the web-app's
|
||||
* context path, and should include the leading <code>/</code>.
|
||||
* Alternatively, inclusion of a scheme name (eg http:// or https://) as the
|
||||
* prefix will denote a fully-qualified URL and this is also supported.</li>
|
||||
* <li><code>authenticationFailureUrl</code> indicates the URL that should be
|
||||
* used for redirection if the authentication request fails. eg:
|
||||
* <code>/login.jsp?login_error=1</code>.</li>
|
||||
* <li><code>filterProcessesUrl</code> indicates the URL that this filter
|
||||
* will respond to. This parameter varies by subclass.</li>
|
||||
* <li><code>alwaysUseDefaultTargetUrl</code> causes successful
|
||||
* authentication to always redirect to the <code>defaultTargetUrl</code>,
|
||||
* even if the <code>HttpSession</code> attribute named {@link
|
||||
* #ACEGI_SAVED_REQUEST_KEY} defines the intended target URL.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* To configure this filter to redirect to specific pages as the result of
|
||||
* specific {@link AuthenticationException}s you can do the following.
|
||||
* Configure the <code>exceptionMappings</code> property in your application
|
||||
* xml. This property is a java.util.Properties object that maps a
|
||||
* fully-qualified exception class name to a redirection url target. For
|
||||
* example:
|
||||
*
|
||||
* <pre>
|
||||
* <property name="exceptionMappings">
|
||||
* <property name="exceptionMappings">
|
||||
* <props>
|
||||
* <prop> key="org.acegisecurity.BadCredentialsException">/bad_credentials.jsp</prop>
|
||||
* <prop> key="org.acegisecurity.BadCredentialsException">/bad_credentials.jsp</prop>
|
||||
* </props>
|
||||
* </property>
|
||||
* </pre>
|
||||
* The example above would redirect all {@link org.acegisecurity.BadCredentialsException}s thrown, to a page in the
|
||||
* web-application called /bad_credentials.jsp.</p>
|
||||
* <p>Any {@link AuthenticationException} thrown that cannot be matched in the <code>exceptionMappings</code> will
|
||||
* be redirected to the <code>authenticationFailureUrl</code></p>
|
||||
* <p>If authentication is successful, an {@link
|
||||
* org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent} will be published to the application
|
||||
* context. No events will be published if authentication was unsuccessful, because this would generally be recorded
|
||||
* via an <code>AuthenticationManager</code>-specific application event.</p>
|
||||
*
|
||||
*
|
||||
* The example above would redirect all
|
||||
* {@link org.acegisecurity.BadCredentialsException}s thrown, to a page in the
|
||||
* web-application called /bad_credentials.jsp.
|
||||
* </p>
|
||||
* <p>
|
||||
* Any {@link AuthenticationException} thrown that cannot be matched in the
|
||||
* <code>exceptionMappings</code> will be redirected to the
|
||||
* <code>authenticationFailureUrl</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* If authentication is successful, an {@link
|
||||
* org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent}
|
||||
* will be published to the application context. No events will be published if
|
||||
* authentication was unsuccessful, because this would generally be recorded via
|
||||
* an <code>AuthenticationManager</code>-specific application event.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AbstractProcessingFilter implements Filter, InitializingBean, ApplicationEventPublisherAware,
|
||||
MessageSourceAware {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
public static final String ACEGI_SAVED_REQUEST_KEY = "ACEGI_SAVED_REQUEST_KEY";
|
||||
public static final String ACEGI_SECURITY_LAST_EXCEPTION_KEY = "ACEGI_SECURITY_LAST_EXCEPTION";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected ApplicationEventPublisher eventPublisher;
|
||||
protected AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||
private AuthenticationManager authenticationManager;
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
|
||||
private Properties exceptionMappings = new Properties();
|
||||
private RememberMeServices rememberMeServices = new NullRememberMeServices();
|
||||
|
||||
/** Where to redirect the browser to if authentication fails */
|
||||
private String authenticationFailureUrl;
|
||||
|
||||
/**
|
||||
* Where to redirect the browser to if authentication is successful but ACEGI_SAVED_REQUEST_KEY is
|
||||
* <code>null</code>
|
||||
*/
|
||||
private String defaultTargetUrl;
|
||||
|
||||
/**
|
||||
* The URL destination that this filter intercepts and processes (usually something like
|
||||
* <code>/j_acegi_security_check</code>)
|
||||
*/
|
||||
private String filterProcessesUrl = getDefaultFilterProcessesUrl();
|
||||
|
||||
/**
|
||||
* If <code>true</code>, will always redirect to the value of {@link #getDefaultTargetUrl} upon successful
|
||||
* authentication, irrespective of the page that caused the authentication request (defaults to <code>false</code>).
|
||||
*/
|
||||
private boolean alwaysUseDefaultTargetUrl = false;
|
||||
|
||||
/**
|
||||
* Indicates if the filter chain should be continued prior to delegation to {@link
|
||||
* #successfulAuthentication(HttpServletRequest, HttpServletResponse, Authentication)}, which may be useful in
|
||||
* certain environment (eg Tapestry). Defaults to <code>false</code>.
|
||||
*/
|
||||
private boolean continueChainBeforeSuccessfulAuthentication = false;
|
||||
|
||||
/**
|
||||
* Specifies the buffer size to use in the event of a directory. A buffer size is used to ensure the
|
||||
* response is not written back to the client immediately. This provides a way for the <code>HttpSession</code>
|
||||
* to be updated before the browser redirect will be sent. Defaults to an 8 Kb buffer.
|
||||
*/
|
||||
private int bufferSize = 8 * 1024;
|
||||
|
||||
/**
|
||||
* If true, causes any redirection URLs to be calculated minus the protocol and context path (defaults to false).
|
||||
*/
|
||||
private boolean useRelativeContext = false;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(filterProcessesUrl, "filterProcessesUrl must be specified");
|
||||
Assert.hasLength(defaultTargetUrl, "defaultTargetUrl must be specified");
|
||||
Assert.hasLength(authenticationFailureUrl, "authenticationFailureUrl must be specified");
|
||||
Assert.notNull(authenticationManager, "authenticationManager must be specified");
|
||||
Assert.notNull(this.rememberMeServices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs actual authentication.
|
||||
*
|
||||
* @param request from which to extract parameters and perform the authentication
|
||||
*
|
||||
* @return the authenticated user
|
||||
*
|
||||
* @throws AuthenticationException if authentication fails
|
||||
*/
|
||||
public abstract Authentication attemptAuthentication(HttpServletRequest request)
|
||||
throws AuthenticationException;
|
||||
|
||||
/**
|
||||
* Does nothing. We use IoC container lifecycle services instead.
|
||||
*/
|
||||
public void destroy() {}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
if (!(request instanceof HttpServletRequest)) {
|
||||
throw new ServletException("Can only process HttpServletRequest");
|
||||
}
|
||||
|
||||
if (!(response instanceof HttpServletResponse)) {
|
||||
throw new ServletException("Can only process HttpServletResponse");
|
||||
}
|
||||
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
|
||||
if (requiresAuthentication(httpRequest, httpResponse)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Request is to process authentication");
|
||||
}
|
||||
|
||||
Authentication authResult;
|
||||
|
||||
try {
|
||||
onPreAuthentication(httpRequest, httpResponse);
|
||||
authResult = attemptAuthentication(httpRequest);
|
||||
} catch (AuthenticationException failed) {
|
||||
// Authentication failed
|
||||
unsuccessfulAuthentication(httpRequest, httpResponse, failed);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Authentication success
|
||||
if (continueChainBeforeSuccessfulAuthentication) {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
successfulAuthentication(httpRequest, httpResponse, authResult);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
public String getAuthenticationFailureUrl() {
|
||||
return authenticationFailureUrl;
|
||||
}
|
||||
|
||||
public AuthenticationManager getAuthenticationManager() {
|
||||
return authenticationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the default <code>filterProcessesUrl</code> for the implementation.
|
||||
*
|
||||
* @return the default <code>filterProcessesUrl</code>
|
||||
*/
|
||||
public abstract String getDefaultFilterProcessesUrl();
|
||||
|
||||
/**
|
||||
* Supplies the default target Url that will be used if no saved request is found or the
|
||||
* <tt>alwaysUseDefaultTargetUrl</tt> propert is set to true.
|
||||
* Override this method of you want to provide a customized default Url (for example if you want different Urls
|
||||
* depending on the authorities of the user who has just logged in).
|
||||
*
|
||||
* @return the defaultTargetUrl property
|
||||
*/
|
||||
public String getDefaultTargetUrl() {
|
||||
return defaultTargetUrl;
|
||||
}
|
||||
|
||||
public Properties getExceptionMappings() {
|
||||
return new Properties(exceptionMappings);
|
||||
}
|
||||
|
||||
public String getFilterProcessesUrl() {
|
||||
return filterProcessesUrl;
|
||||
}
|
||||
|
||||
public RememberMeServices getRememberMeServices() {
|
||||
return rememberMeServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing. We use IoC container lifecycle services instead.
|
||||
*
|
||||
* @param arg0 ignored
|
||||
*
|
||||
* @throws ServletException ignored
|
||||
*/
|
||||
public void init(FilterConfig arg0) throws ServletException {}
|
||||
|
||||
public boolean isAlwaysUseDefaultTargetUrl() {
|
||||
return alwaysUseDefaultTargetUrl;
|
||||
}
|
||||
|
||||
public boolean isContinueChainBeforeSuccessfulAuthentication() {
|
||||
return continueChainBeforeSuccessfulAuthentication;
|
||||
}
|
||||
|
||||
public static String obtainFullRequestUrl(HttpServletRequest request) {
|
||||
SavedRequest savedRequest = (SavedRequest) request.getSession()
|
||||
.getAttribute(AbstractProcessingFilter.ACEGI_SAVED_REQUEST_KEY);
|
||||
|
||||
return (savedRequest == null) ? null : savedRequest.getFullRequestUrl();
|
||||
}
|
||||
|
||||
protected void onPreAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException, IOException {}
|
||||
|
||||
protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authResult) throws IOException {}
|
||||
|
||||
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException failed) throws IOException {}
|
||||
|
||||
/**
|
||||
* <p>Indicates whether this filter should attempt to process a login request for the current invocation.</p>
|
||||
* <p>It strips any parameters from the "path" section of the request URL (such as the jsessionid
|
||||
* parameter in <em>http://host/myapp/index.html;jsessionid=blah</em>) before matching against the
|
||||
* <code>filterProcessesUrl</code> property.</p>
|
||||
* <p>Subclasses may override for special requirements, such as Tapestry integration.</p>
|
||||
*
|
||||
* @param request as received from the filter chain
|
||||
* @param response as received from the filter chain
|
||||
*
|
||||
* @return <code>true</code> if the filter should attempt authentication, <code>false</code> otherwise
|
||||
*/
|
||||
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
|
||||
String uri = request.getRequestURI();
|
||||
int pathParamIndex = uri.indexOf(';');
|
||||
|
||||
if (pathParamIndex > 0) {
|
||||
// strip everything after the first semi-colon
|
||||
uri = uri.substring(0, pathParamIndex);
|
||||
}
|
||||
|
||||
if ("".equals(request.getContextPath())) {
|
||||
return uri.endsWith(filterProcessesUrl);
|
||||
}
|
||||
|
||||
return uri.endsWith(request.getContextPath() + filterProcessesUrl);
|
||||
}
|
||||
|
||||
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
|
||||
throws IOException {
|
||||
String finalUrl;
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
if (useRelativeContext) {
|
||||
finalUrl = url;
|
||||
} else {
|
||||
finalUrl = request.getContextPath() + url;
|
||||
}
|
||||
} else if (useRelativeContext) {
|
||||
// Calculate the relative URL from the fully qualifed URL, minus the protocol and base context.
|
||||
int len = request.getContextPath().length();
|
||||
int index = url.indexOf(request.getContextPath()) + len;
|
||||
finalUrl = url.substring(index);
|
||||
if (finalUrl.length() > 1 && finalUrl.charAt(0) == '/') {
|
||||
finalUrl = finalUrl.substring( 1 );
|
||||
}
|
||||
} else {
|
||||
finalUrl = url;
|
||||
}
|
||||
|
||||
Assert.isTrue(!response.isCommitted(), "Response already committed; the authentication mechanism must be able to modify buffer size");
|
||||
response.setBufferSize(bufferSize);
|
||||
response.sendRedirect(response.encodeRedirectURL(finalUrl));
|
||||
}
|
||||
|
||||
public void setAlwaysUseDefaultTargetUrl(boolean alwaysUseDefaultTargetUrl) {
|
||||
this.alwaysUseDefaultTargetUrl = alwaysUseDefaultTargetUrl;
|
||||
}
|
||||
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
|
||||
public void setAuthenticationFailureUrl(String authenticationFailureUrl) {
|
||||
this.authenticationFailureUrl = authenticationFailureUrl;
|
||||
}
|
||||
|
||||
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
|
||||
public void setContinueChainBeforeSuccessfulAuthentication(boolean continueChainBeforeSuccessfulAuthentication) {
|
||||
this.continueChainBeforeSuccessfulAuthentication = continueChainBeforeSuccessfulAuthentication;
|
||||
}
|
||||
|
||||
public void setDefaultTargetUrl(String defaultTargetUrl) {
|
||||
Assert.isTrue(defaultTargetUrl.startsWith("/") | defaultTargetUrl.startsWith("http"),
|
||||
"defaultTarget must start with '/' or with 'http(s)'");
|
||||
this.defaultTargetUrl = defaultTargetUrl;
|
||||
}
|
||||
|
||||
public void setExceptionMappings(Properties exceptionMappings) {
|
||||
this.exceptionMappings = exceptionMappings;
|
||||
}
|
||||
|
||||
public void setFilterProcessesUrl(String filterProcessesUrl) {
|
||||
this.filterProcessesUrl = filterProcessesUrl;
|
||||
}
|
||||
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
|
||||
public void setRememberMeServices(RememberMeServices rememberMeServices) {
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authResult) throws IOException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication success: " + authResult.toString());
|
||||
}
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(authResult);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Updated SecurityContextHolder to contain the following Authentication: '" + authResult + "'");
|
||||
}
|
||||
|
||||
String targetUrl = determineTargetUrl(request);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Redirecting to target URL from HTTP Session (or default): " + targetUrl);
|
||||
}
|
||||
|
||||
onSuccessfulAuthentication(request, response, authResult);
|
||||
|
||||
rememberMeServices.loginSuccess(request, response, authResult);
|
||||
|
||||
// Fire event
|
||||
if (this.eventPublisher != null) {
|
||||
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
|
||||
}
|
||||
|
||||
sendRedirect(request, response, targetUrl);
|
||||
}
|
||||
|
||||
protected String determineTargetUrl(HttpServletRequest request) {
|
||||
// Don't attempt to obtain the url from the saved request if alwaysUsedefaultTargetUrl is set
|
||||
String targetUrl = alwaysUseDefaultTargetUrl ? null : obtainFullRequestUrl(request);
|
||||
|
||||
if (targetUrl == null) {
|
||||
targetUrl = getDefaultTargetUrl();
|
||||
}
|
||||
|
||||
return targetUrl;
|
||||
}
|
||||
|
||||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException failed) throws IOException {
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
MessageSourceAware, ApplicationContextAware {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
public static final String ACEGI_SAVED_REQUEST_KEY = "ACEGI_SAVED_REQUEST_KEY";
|
||||
|
||||
public static final String ACEGI_SECURITY_LAST_EXCEPTION_KEY = "ACEGI_SECURITY_LAST_EXCEPTION";
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
protected ApplicationEventPublisher eventPublisher;
|
||||
|
||||
protected AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
|
||||
|
||||
private Properties exceptionMappings = new Properties();
|
||||
|
||||
private RememberMeServices rememberMeServices = new NullRememberMeServices();
|
||||
|
||||
/** Where to redirect the browser to if authentication fails */
|
||||
private String authenticationFailureUrl;
|
||||
|
||||
/**
|
||||
* Where to redirect the browser to if authentication is successful but
|
||||
* ACEGI_SAVED_REQUEST_KEY is <code>null</code>
|
||||
*/
|
||||
private String defaultTargetUrl;
|
||||
|
||||
/**
|
||||
* The URL destination that this filter intercepts and processes (usually
|
||||
* something like <code>/j_acegi_security_check</code>)
|
||||
*/
|
||||
private String filterProcessesUrl = getDefaultFilterProcessesUrl();
|
||||
|
||||
/**
|
||||
* If <code>true</code>, will always redirect to the value of
|
||||
* {@link #getDefaultTargetUrl} upon successful authentication, irrespective
|
||||
* of the page that caused the authentication request (defaults to
|
||||
* <code>false</code>).
|
||||
*/
|
||||
private boolean alwaysUseDefaultTargetUrl = false;
|
||||
|
||||
/**
|
||||
* Indicates if the filter chain should be continued prior to delegation to
|
||||
* {@link #successfulAuthentication(HttpServletRequest, HttpServletResponse,
|
||||
* Authentication)}, which may be useful in certain environment (eg
|
||||
* Tapestry). Defaults to <code>false</code>.
|
||||
*/
|
||||
private boolean continueChainBeforeSuccessfulAuthentication = false;
|
||||
|
||||
/**
|
||||
* Specifies the buffer size to use in the event of a directory. A buffer
|
||||
* size is used to ensure the response is not written back to the client
|
||||
* immediately. This provides a way for the <code>HttpSession</code> to be
|
||||
* updated before the browser redirect will be sent. Defaults to an 8 Kb
|
||||
* buffer.
|
||||
*/
|
||||
private int bufferSize = 8 * 1024;
|
||||
|
||||
/**
|
||||
* If true, causes any redirection URLs to be calculated minus the protocol
|
||||
* and context path (defaults to false).
|
||||
*/
|
||||
private boolean useRelativeContext = false;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private boolean isSetAuthenticationManagerInvoked = false;
|
||||
|
||||
private boolean isSetRememberMeServicesInvoked = false;
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(filterProcessesUrl, "filterProcessesUrl must be specified");
|
||||
Assert.hasLength(defaultTargetUrl, "defaultTargetUrl must be specified");
|
||||
Assert.hasLength(authenticationFailureUrl, "authenticationFailureUrl must be specified");
|
||||
if (!isSetAuthenticationManagerInvoked) {
|
||||
autoDetectAuthenticationManager();
|
||||
}
|
||||
if (!isSetRememberMeServicesInvoked) {
|
||||
autoDetectRememberMeServices();
|
||||
}
|
||||
Assert.notNull(authenticationManager, "authenticationManager must be specified");
|
||||
Assert.notNull(this.rememberMeServices);
|
||||
}
|
||||
|
||||
private void autoDetectRememberMeServices() {
|
||||
if (applicationContext != null) {
|
||||
Map map = applicationContext.getBeansOfType(RememberMeServices.class);
|
||||
if (map.size() > 0) {
|
||||
setRememberMeServices((RememberMeServices) map.values().iterator().next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Introspects the <code>Applicationcontext</code> for the single instance
|
||||
* of <code>AuthenticationManager</code>. If found invoke
|
||||
* setAuthenticationManager method by providing the found instance of
|
||||
* authenticationManager as a method parameter. If more than one instance of
|
||||
* <code>AuthenticationManager</code> is found, the method throws
|
||||
* <code>IllegalStateException</code>.
|
||||
*
|
||||
* @param applicationContext to locate the instance
|
||||
*/
|
||||
private void autoDetectAuthenticationManager() {
|
||||
if (applicationContext != null) {
|
||||
Map map = applicationContext.getBeansOfType(AuthenticationManager.class);
|
||||
if (map.size() > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"More than one AuthenticationManager beans detected please refer to the one using "
|
||||
+ " [ authenticationManager ] " + "property");
|
||||
}
|
||||
else if (map.size() == 1) {
|
||||
setAuthenticationManager((AuthenticationManager) map.values().iterator().next());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs actual authentication.
|
||||
*
|
||||
* @param request from which to extract parameters and perform the
|
||||
* authentication
|
||||
*
|
||||
* @return the authenticated user
|
||||
*
|
||||
* @throws AuthenticationException if authentication fails
|
||||
*/
|
||||
public abstract Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException;
|
||||
|
||||
/**
|
||||
* Does nothing. We use IoC container lifecycle services instead.
|
||||
*/
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
|
||||
ServletException {
|
||||
if (!(request instanceof HttpServletRequest)) {
|
||||
throw new ServletException("Can only process HttpServletRequest");
|
||||
}
|
||||
|
||||
if (!(response instanceof HttpServletResponse)) {
|
||||
throw new ServletException("Can only process HttpServletResponse");
|
||||
}
|
||||
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
|
||||
if (requiresAuthentication(httpRequest, httpResponse)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Request is to process authentication");
|
||||
}
|
||||
|
||||
Authentication authResult;
|
||||
|
||||
try {
|
||||
onPreAuthentication(httpRequest, httpResponse);
|
||||
authResult = attemptAuthentication(httpRequest);
|
||||
}
|
||||
catch (AuthenticationException failed) {
|
||||
// Authentication failed
|
||||
unsuccessfulAuthentication(httpRequest, httpResponse, failed);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Authentication success
|
||||
if (continueChainBeforeSuccessfulAuthentication) {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
successfulAuthentication(httpRequest, httpResponse, authResult);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
public String getAuthenticationFailureUrl() {
|
||||
return authenticationFailureUrl;
|
||||
}
|
||||
|
||||
public AuthenticationManager getAuthenticationManager() {
|
||||
return authenticationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the default <code>filterProcessesUrl</code> for the
|
||||
* implementation.
|
||||
*
|
||||
* @return the default <code>filterProcessesUrl</code>
|
||||
*/
|
||||
public abstract String getDefaultFilterProcessesUrl();
|
||||
|
||||
/**
|
||||
* Supplies the default target Url that will be used if no saved request is
|
||||
* found or the <tt>alwaysUseDefaultTargetUrl</tt> propert is set to true.
|
||||
* Override this method of you want to provide a customized default Url (for
|
||||
* example if you want different Urls depending on the authorities of the
|
||||
* user who has just logged in).
|
||||
*
|
||||
* @return the defaultTargetUrl property
|
||||
*/
|
||||
public String getDefaultTargetUrl() {
|
||||
return defaultTargetUrl;
|
||||
}
|
||||
|
||||
public Properties getExceptionMappings() {
|
||||
return new Properties(exceptionMappings);
|
||||
}
|
||||
|
||||
public String getFilterProcessesUrl() {
|
||||
return filterProcessesUrl;
|
||||
}
|
||||
|
||||
public RememberMeServices getRememberMeServices() {
|
||||
return rememberMeServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing. We use IoC container lifecycle services instead.
|
||||
*
|
||||
* @param arg0 ignored
|
||||
*
|
||||
* @throws ServletException ignored
|
||||
*/
|
||||
public void init(FilterConfig arg0) throws ServletException {
|
||||
}
|
||||
|
||||
public boolean isAlwaysUseDefaultTargetUrl() {
|
||||
return alwaysUseDefaultTargetUrl;
|
||||
}
|
||||
|
||||
public boolean isContinueChainBeforeSuccessfulAuthentication() {
|
||||
return continueChainBeforeSuccessfulAuthentication;
|
||||
}
|
||||
|
||||
public static String obtainFullRequestUrl(HttpServletRequest request) {
|
||||
SavedRequest savedRequest = (SavedRequest) request.getSession().getAttribute(
|
||||
AbstractProcessingFilter.ACEGI_SAVED_REQUEST_KEY);
|
||||
|
||||
return (savedRequest == null) ? null : savedRequest.getFullRequestUrl();
|
||||
}
|
||||
|
||||
protected void onPreAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException, IOException {
|
||||
}
|
||||
|
||||
protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authResult) throws IOException {
|
||||
}
|
||||
|
||||
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException failed) throws IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Indicates whether this filter should attempt to process a login request
|
||||
* for the current invocation.
|
||||
* </p>
|
||||
* <p>
|
||||
* It strips any parameters from the "path" section of the request URL (such
|
||||
* as the jsessionid parameter in
|
||||
* <em>http://host/myapp/index.html;jsessionid=blah</em>) before matching
|
||||
* against the <code>filterProcessesUrl</code> property.
|
||||
* </p>
|
||||
* <p>
|
||||
* Subclasses may override for special requirements, such as Tapestry
|
||||
* integration.
|
||||
* </p>
|
||||
*
|
||||
* @param request as received from the filter chain
|
||||
* @param response as received from the filter chain
|
||||
*
|
||||
* @return <code>true</code> if the filter should attempt authentication,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
|
||||
String uri = request.getRequestURI();
|
||||
int pathParamIndex = uri.indexOf(';');
|
||||
|
||||
if (pathParamIndex > 0) {
|
||||
// strip everything after the first semi-colon
|
||||
uri = uri.substring(0, pathParamIndex);
|
||||
}
|
||||
|
||||
if ("".equals(request.getContextPath())) {
|
||||
return uri.endsWith(filterProcessesUrl);
|
||||
}
|
||||
|
||||
return uri.endsWith(request.getContextPath() + filterProcessesUrl);
|
||||
}
|
||||
|
||||
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
|
||||
throws IOException {
|
||||
String finalUrl;
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
if (useRelativeContext) {
|
||||
finalUrl = url;
|
||||
}
|
||||
else {
|
||||
finalUrl = request.getContextPath() + url;
|
||||
}
|
||||
}
|
||||
else if (useRelativeContext) {
|
||||
// Calculate the relative URL from the fully qualifed URL, minus the
|
||||
// protocol and base context.
|
||||
int len = request.getContextPath().length();
|
||||
int index = url.indexOf(request.getContextPath()) + len;
|
||||
finalUrl = url.substring(index);
|
||||
if (finalUrl.length() > 1 && finalUrl.charAt(0) == '/') {
|
||||
finalUrl = finalUrl.substring(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
finalUrl = url;
|
||||
}
|
||||
|
||||
Assert.isTrue(!response.isCommitted(),
|
||||
"Response already committed; the authentication mechanism must be able to modify buffer size");
|
||||
response.setBufferSize(bufferSize);
|
||||
response.sendRedirect(response.encodeRedirectURL(finalUrl));
|
||||
}
|
||||
|
||||
public void setAlwaysUseDefaultTargetUrl(boolean alwaysUseDefaultTargetUrl) {
|
||||
this.alwaysUseDefaultTargetUrl = alwaysUseDefaultTargetUrl;
|
||||
}
|
||||
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
|
||||
public void setAuthenticationFailureUrl(String authenticationFailureUrl) {
|
||||
this.authenticationFailureUrl = authenticationFailureUrl;
|
||||
}
|
||||
|
||||
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
|
||||
public void setContinueChainBeforeSuccessfulAuthentication(boolean continueChainBeforeSuccessfulAuthentication) {
|
||||
this.continueChainBeforeSuccessfulAuthentication = continueChainBeforeSuccessfulAuthentication;
|
||||
}
|
||||
|
||||
public void setDefaultTargetUrl(String defaultTargetUrl) {
|
||||
Assert.isTrue(defaultTargetUrl.startsWith("/") | defaultTargetUrl.startsWith("http"),
|
||||
"defaultTarget must start with '/' or with 'http(s)'");
|
||||
this.defaultTargetUrl = defaultTargetUrl;
|
||||
}
|
||||
|
||||
public void setExceptionMappings(Properties exceptionMappings) {
|
||||
this.exceptionMappings = exceptionMappings;
|
||||
}
|
||||
|
||||
public void setFilterProcessesUrl(String filterProcessesUrl) {
|
||||
this.filterProcessesUrl = filterProcessesUrl;
|
||||
}
|
||||
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
|
||||
public void setRememberMeServices(RememberMeServices rememberMeServices) {
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authResult) throws IOException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication success: " + authResult.toString());
|
||||
}
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(authResult);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Updated SecurityContextHolder to contain the following Authentication: '" + authResult + "'");
|
||||
}
|
||||
|
||||
String targetUrl = determineTargetUrl(request);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Redirecting to target URL from HTTP Session (or default): " + targetUrl);
|
||||
}
|
||||
|
||||
onSuccessfulAuthentication(request, response, authResult);
|
||||
|
||||
rememberMeServices.loginSuccess(request, response, authResult);
|
||||
|
||||
// Fire event
|
||||
if (this.eventPublisher != null) {
|
||||
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
|
||||
}
|
||||
|
||||
sendRedirect(request, response, targetUrl);
|
||||
}
|
||||
|
||||
protected String determineTargetUrl(HttpServletRequest request) {
|
||||
// Don't attempt to obtain the url from the saved request if
|
||||
// alwaysUsedefaultTargetUrl is set
|
||||
String targetUrl = alwaysUseDefaultTargetUrl ? null : obtainFullRequestUrl(request);
|
||||
|
||||
if (targetUrl == null) {
|
||||
targetUrl = getDefaultTargetUrl();
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Updated SecurityContextHolder to contain null Authentication");
|
||||
}
|
||||
return targetUrl;
|
||||
}
|
||||
|
||||
String failureUrl = exceptionMappings.getProperty(failed.getClass().getName(), authenticationFailureUrl);
|
||||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException failed) throws IOException {
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request failed: " + failed.toString());
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Updated SecurityContextHolder to contain null Authentication");
|
||||
}
|
||||
|
||||
try {
|
||||
request.getSession().setAttribute(ACEGI_SECURITY_LAST_EXCEPTION_KEY, failed);
|
||||
} catch (Exception ignored) {}
|
||||
String failureUrl = exceptionMappings.getProperty(failed.getClass().getName(), authenticationFailureUrl);
|
||||
|
||||
onUnsuccessfulAuthentication(request, response, failed);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request failed: " + failed.toString());
|
||||
}
|
||||
|
||||
rememberMeServices.loginFail(request, response);
|
||||
try {
|
||||
request.getSession().setAttribute(ACEGI_SECURITY_LAST_EXCEPTION_KEY, failed);
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
}
|
||||
|
||||
sendRedirect(request, response, failureUrl);
|
||||
}
|
||||
onUnsuccessfulAuthentication(request, response, failed);
|
||||
|
||||
public AuthenticationDetailsSource getAuthenticationDetailsSource() {
|
||||
// Required due to SEC-310
|
||||
return authenticationDetailsSource;
|
||||
}
|
||||
rememberMeServices.loginFail(request, response);
|
||||
|
||||
sendRedirect(request, response, failureUrl);
|
||||
}
|
||||
|
||||
public AuthenticationDetailsSource getAuthenticationDetailsSource() {
|
||||
// Required due to SEC-310
|
||||
return authenticationDetailsSource;
|
||||
}
|
||||
|
||||
public void setBufferSize(int bufferSize) {
|
||||
this.bufferSize = bufferSize;
|
||||
|
@ -480,4 +596,9 @@ public abstract class AbstractProcessingFilter implements Filter, InitializingBe
|
|||
public void setUseRelativeContext(boolean useRelativeContext) {
|
||||
this.useRelativeContext = useRelativeContext;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,11 +32,15 @@ import org.acegisecurity.util.PortResolverImpl;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
|
@ -47,185 +51,277 @@ import javax.servlet.ServletResponse;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Handles any <code>AccessDeniedException</code> and <code>AuthenticationException</code> thrown within the filter
|
||||
* chain.<p>This filter is necessary because it provides the bridge between Java exceptions and HTTP responses. It
|
||||
* is solely concerned with maintaining the user interface. This filter does not do any actual security enforcement.</p>
|
||||
* <p>If an {@link AuthenticationException} is detected, the filter will launch the
|
||||
* <code>authenticationEntryPoint</code>. This allows common handling of authentication failures originating from any
|
||||
* subclass of {@link org.acegisecurity.intercept.AbstractSecurityInterceptor}.</p>
|
||||
* <p>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 delegate to the {@link org.acegisecurity.ui.AccessDeniedHandler}. By
|
||||
* default the filter will use {@link org.acegisecurity.ui.AccessDeniedHandlerImpl}.</p>
|
||||
* <p>To use this filter, it is necessary to specify the following properties:</p>
|
||||
* <ul>
|
||||
* <li><code>authenticationEntryPoint</code> indicates the handler that should commence the authentication
|
||||
* process if an <code>AuthenticationException</code> is detected. Note that this may also switch the current
|
||||
* protocol from http to https for an SSL login.</li>
|
||||
* <li><code>portResolver</code> is used to determine the "real" port that a request was received on.</li>
|
||||
* </ul>
|
||||
* <P><B>Do not use this class directly.</B> Instead configure <code>web.xml</code> to use the {@link
|
||||
* org.acegisecurity.util.FilterToBeanProxy}.</p>
|
||||
*
|
||||
* Handles any <code>AccessDeniedException</code> and
|
||||
* <code>AuthenticationException</code> thrown within the filter chain.
|
||||
* <p>
|
||||
* This filter is necessary because it provides the bridge between Java
|
||||
* exceptions and HTTP responses. It is solely concerned with maintaining the
|
||||
* user interface. This filter does not do any actual security enforcement.
|
||||
* </p>
|
||||
* <p>
|
||||
* If an {@link AuthenticationException} is detected, the filter will launch the
|
||||
* <code>authenticationEntryPoint</code>. This allows common handling of
|
||||
* authentication failures originating from any subclass of
|
||||
* {@link org.acegisecurity.intercept.AbstractSecurityInterceptor}.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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 delegate to the
|
||||
* {@link org.acegisecurity.ui.AccessDeniedHandler}. By default the filter will
|
||||
* use {@link org.acegisecurity.ui.AccessDeniedHandlerImpl}.
|
||||
* </p>
|
||||
* <p>
|
||||
* To use this filter, it is necessary to specify the following properties:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><code>authenticationEntryPoint</code> indicates the handler that
|
||||
* should commence the authentication process if an
|
||||
* <code>AuthenticationException</code> is detected. Note that this may also
|
||||
* switch the current protocol from http to https for an SSL login.</li>
|
||||
* <li><code>portResolver</code> is used to determine the "real" port that a
|
||||
* request was received on.</li>
|
||||
* </ul>
|
||||
* <P>
|
||||
* <B>Do not use this class directly.</B> Instead configure
|
||||
* <code>web.xml</code> to use the {@link
|
||||
* org.acegisecurity.util.FilterToBeanProxy}.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author colin sampaleanu
|
||||
* @version $Id$
|
||||
* @version $Id: ExceptionTranslationFilter.java 1496 2006-05-23 13:38:33Z
|
||||
* benalex $
|
||||
*/
|
||||
public class ExceptionTranslationFilter implements Filter, InitializingBean {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
public class ExceptionTranslationFilter implements Filter, InitializingBean, ApplicationContextAware {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ExceptionTranslationFilter.class);
|
||||
private static final Log logger = LogFactory.getLog(ExceptionTranslationFilter.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
||||
private PortResolver portResolver = new PortResolverImpl();
|
||||
private boolean createSessionAllowed = true;
|
||||
private AccessDeniedHandler accessDeniedHandler;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(authenticationEntryPoint, "authenticationEntryPoint must be specified");
|
||||
Assert.notNull(portResolver, "portResolver must be specified");
|
||||
Assert.notNull(authenticationTrustResolver, "authenticationTrustResolver must be specified");
|
||||
}
|
||||
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
||||
|
||||
public void destroy() {}
|
||||
private PortResolver portResolver = new PortResolverImpl();
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
if (!(request instanceof HttpServletRequest)) {
|
||||
throw new ServletException("HttpServletRequest required");
|
||||
}
|
||||
private boolean createSessionAllowed = true;
|
||||
|
||||
if (!(response instanceof HttpServletResponse)) {
|
||||
throw new ServletException("HttpServletResponse required");
|
||||
}
|
||||
/*
|
||||
* applicationContext will be inject as a part of the contract of
|
||||
* ApplicationContextAware interface
|
||||
*/
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
try {
|
||||
chain.doFilter(request, response);
|
||||
/*
|
||||
* boolean field to track if setter for accessDeniedHandler is invoked. If
|
||||
* invoked the default value changes to true
|
||||
*/
|
||||
private boolean isSetAcessDeniedHandlerInvoked = false;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Chain processed normally");
|
||||
}
|
||||
} catch (AuthenticationException ex) {
|
||||
handleException(request, response, chain, ex);
|
||||
} catch (AccessDeniedException ex) {
|
||||
handleException(request, response, chain, ex);
|
||||
} catch (ServletException ex) {
|
||||
if (ex.getRootCause() instanceof AuthenticationException
|
||||
|| ex.getRootCause() instanceof AccessDeniedException) {
|
||||
handleException(request, response, chain, (AcegiSecurityException) ex.getRootCause());
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public AuthenticationEntryPoint getAuthenticationEntryPoint() {
|
||||
return authenticationEntryPoint;
|
||||
}
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(authenticationEntryPoint, "authenticationEntryPoint must be specified");
|
||||
Assert.notNull(portResolver, "portResolver must be specified");
|
||||
Assert.notNull(authenticationTrustResolver, "authenticationTrustResolver must be specified");
|
||||
|
||||
public AuthenticationTrustResolver getAuthenticationTrustResolver() {
|
||||
return authenticationTrustResolver;
|
||||
}
|
||||
// autodetect AccessDeniedHandler instance in the applicationcontext if
|
||||
// it wasn't injected.
|
||||
if (!isSetAcessDeniedHandlerInvoked) {
|
||||
if (applicationContext != null) {
|
||||
autoDetectAnyAccessDeniedHandlerAndUseIt(applicationContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PortResolver getPortResolver() {
|
||||
return portResolver;
|
||||
}
|
||||
/**
|
||||
* Introspects the <code>Applicationcontext</code> for the single instance
|
||||
* of {@link AccessDeniedHandler}. If found invoke
|
||||
* setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) method by
|
||||
* providing the found instance of accessDeniedHandler as a method
|
||||
* parameter. If more than one instance of <code>AccessDeniedHandler</code>
|
||||
* is found, the method throws <code>IllegalStateException</code>.
|
||||
*
|
||||
* @param applicationContext to locate the instance
|
||||
*/
|
||||
private void autoDetectAnyAccessDeniedHandlerAndUseIt(ApplicationContext applicationContext) {
|
||||
Map map = applicationContext.getBeansOfType(AccessDeniedHandler.class);
|
||||
if (map.size() > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"More than one AccessDeniedHandler beans detected please refer to the one using "
|
||||
+ " [ accessDeniedBeanRef ] " + "attribute");
|
||||
}
|
||||
else if (map.size() == 1) {
|
||||
AccessDeniedHandler handler = (AccessDeniedHandlerImpl) map.values().iterator().next();
|
||||
setAccessDeniedHandler(handler);
|
||||
}
|
||||
else {
|
||||
// create and use the default one specified as an instance variable.
|
||||
accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||
}
|
||||
|
||||
private void handleException(ServletRequest request, ServletResponse response, FilterChain chain,
|
||||
AcegiSecurityException exception) throws IOException, ServletException {
|
||||
if (exception instanceof AuthenticationException) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication exception occurred; redirecting to authentication entry point", exception);
|
||||
}
|
||||
}
|
||||
|
||||
sendStartAuthentication(request, response, chain, (AuthenticationException) exception);
|
||||
} else if (exception instanceof AccessDeniedException) {
|
||||
if (authenticationTrustResolver.isAnonymous(SecurityContextHolder.getContext().getAuthentication())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point",
|
||||
exception);
|
||||
}
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
sendStartAuthentication(request, response, chain,
|
||||
new InsufficientAuthenticationException("Full authentication is required to access this resource"));
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Access is denied (user is not anonymous); delegating to AccessDeniedHandler",
|
||||
exception);
|
||||
}
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
|
||||
ServletException {
|
||||
if (!(request instanceof HttpServletRequest)) {
|
||||
throw new ServletException("HttpServletRequest required");
|
||||
}
|
||||
|
||||
accessDeniedHandler.handle(request, response, (AccessDeniedException) exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(response instanceof HttpServletResponse)) {
|
||||
throw new ServletException("HttpServletResponse required");
|
||||
}
|
||||
|
||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||
try {
|
||||
chain.doFilter(request, response);
|
||||
|
||||
/**
|
||||
* If <code>true</code>, indicates that <code>SecurityEnforcementFilter</code> is permitted to store the
|
||||
* target URL and exception information in the <code>HttpSession</code> (the default). In situations where you do
|
||||
* not wish to unnecessarily create <code>HttpSession</code>s - because the user agent will know the failed URL,
|
||||
* such as with BASIC or Digest authentication - you may wish to set this property to <code>false</code>. Remember
|
||||
* to also set the {@link org.acegisecurity.context.HttpSessionContextIntegrationFilter#allowSessionCreation} to
|
||||
* <code>false</code> if you set this property to <code>false</code>.
|
||||
*
|
||||
* @return <code>true</code> if the <code>HttpSession</code> will be used to store information about the failed
|
||||
* request, <code>false</code> if the <code>HttpSession</code> will not be used
|
||||
*/
|
||||
public boolean isCreateSessionAllowed() {
|
||||
return createSessionAllowed;
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Chain processed normally");
|
||||
}
|
||||
}
|
||||
catch (AuthenticationException ex) {
|
||||
handleException(request, response, chain, ex);
|
||||
}
|
||||
catch (AccessDeniedException ex) {
|
||||
handleException(request, response, chain, ex);
|
||||
}
|
||||
catch (ServletException ex) {
|
||||
if (ex.getRootCause() instanceof AuthenticationException
|
||||
|| ex.getRootCause() instanceof AccessDeniedException) {
|
||||
handleException(request, response, chain, (AcegiSecurityException) ex.getRootCause());
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
protected void sendStartAuthentication(ServletRequest request, ServletResponse response, FilterChain chain,
|
||||
AuthenticationException reason) throws ServletException, IOException {
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
public AuthenticationEntryPoint getAuthenticationEntryPoint() {
|
||||
return authenticationEntryPoint;
|
||||
}
|
||||
|
||||
SavedRequest savedRequest = new SavedRequest(httpRequest, portResolver);
|
||||
public AuthenticationTrustResolver getAuthenticationTrustResolver() {
|
||||
return authenticationTrustResolver;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication entry point being called; SavedRequest added to Session: " + savedRequest);
|
||||
}
|
||||
public PortResolver getPortResolver() {
|
||||
return portResolver;
|
||||
}
|
||||
|
||||
if (createSessionAllowed) {
|
||||
// Store the HTTP request itself. Used by AbstractProcessingFilter
|
||||
// for redirection after successful authentication (SEC-29)
|
||||
httpRequest.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SAVED_REQUEST_KEY, savedRequest);
|
||||
}
|
||||
private void handleException(ServletRequest request, ServletResponse response, FilterChain chain,
|
||||
AcegiSecurityException exception) throws IOException, ServletException {
|
||||
if (exception instanceof AuthenticationException) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication exception occurred; redirecting to authentication entry point", exception);
|
||||
}
|
||||
|
||||
// SEC-112: Clear the SecurityContextHolder's Authentication, as the
|
||||
// existing Authentication is no longer considered valid
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
sendStartAuthentication(request, response, chain, (AuthenticationException) exception);
|
||||
}
|
||||
else if (exception instanceof AccessDeniedException) {
|
||||
if (authenticationTrustResolver.isAnonymous(SecurityContextHolder.getContext().getAuthentication())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point",
|
||||
exception);
|
||||
}
|
||||
|
||||
authenticationEntryPoint.commence(httpRequest, (HttpServletResponse) response, reason);
|
||||
}
|
||||
sendStartAuthentication(request, response, chain, new InsufficientAuthenticationException(
|
||||
"Full authentication is required to access this resource"));
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Access is denied (user is not anonymous); delegating to AccessDeniedHandler",
|
||||
exception);
|
||||
}
|
||||
|
||||
public void setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
|
||||
Assert.notNull(accessDeniedHandler, "AccessDeniedHandler required");
|
||||
this.accessDeniedHandler = accessDeniedHandler;
|
||||
}
|
||||
accessDeniedHandler.handle(request, response, (AccessDeniedException) exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setAuthenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
|
||||
this.authenticationEntryPoint = authenticationEntryPoint;
|
||||
}
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) {
|
||||
this.authenticationTrustResolver = authenticationTrustResolver;
|
||||
}
|
||||
/**
|
||||
* If <code>true</code>, indicates that
|
||||
* <code>SecurityEnforcementFilter</code> is permitted to store the target
|
||||
* URL and exception information in the <code>HttpSession</code> (the
|
||||
* default). In situations where you do not wish to unnecessarily create
|
||||
* <code>HttpSession</code>s - because the user agent will know the
|
||||
* failed URL, such as with BASIC or Digest authentication - you may wish to
|
||||
* set this property to <code>false</code>. Remember to also set the
|
||||
* {@link org.acegisecurity.context.HttpSessionContextIntegrationFilter#allowSessionCreation}
|
||||
* to <code>false</code> if you set this property to <code>false</code>.
|
||||
*
|
||||
* @return <code>true</code> if the <code>HttpSession</code> will be
|
||||
* used to store information about the failed request, <code>false</code>
|
||||
* if the <code>HttpSession</code> will not be used
|
||||
*/
|
||||
public boolean isCreateSessionAllowed() {
|
||||
return createSessionAllowed;
|
||||
}
|
||||
|
||||
public void setCreateSessionAllowed(boolean createSessionAllowed) {
|
||||
this.createSessionAllowed = createSessionAllowed;
|
||||
}
|
||||
protected void sendStartAuthentication(ServletRequest request, ServletResponse response, FilterChain chain,
|
||||
AuthenticationException reason) throws ServletException, IOException {
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
|
||||
SavedRequest savedRequest = new SavedRequest(httpRequest, portResolver);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication entry point being called; SavedRequest added to Session: " + savedRequest);
|
||||
}
|
||||
|
||||
if (createSessionAllowed) {
|
||||
// Store the HTTP request itself. Used by AbstractProcessingFilter
|
||||
// for redirection after successful authentication (SEC-29)
|
||||
httpRequest.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SAVED_REQUEST_KEY, savedRequest);
|
||||
}
|
||||
|
||||
// SEC-112: Clear the SecurityContextHolder's Authentication, as the
|
||||
// existing Authentication is no longer considered valid
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
|
||||
authenticationEntryPoint.commence(httpRequest, (HttpServletResponse) response, reason);
|
||||
}
|
||||
|
||||
public void setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
|
||||
Assert.notNull(accessDeniedHandler, "AccessDeniedHandler required");
|
||||
this.accessDeniedHandler = accessDeniedHandler;
|
||||
this.isSetAcessDeniedHandlerInvoked = true;
|
||||
}
|
||||
|
||||
public void setAuthenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
|
||||
this.authenticationEntryPoint = authenticationEntryPoint;
|
||||
}
|
||||
|
||||
public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) {
|
||||
this.authenticationTrustResolver = authenticationTrustResolver;
|
||||
}
|
||||
|
||||
public void setCreateSessionAllowed(boolean createSessionAllowed) {
|
||||
this.createSessionAllowed = createSessionAllowed;
|
||||
}
|
||||
|
||||
public void setPortResolver(PortResolver portResolver) {
|
||||
this.portResolver = portResolver;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public void setPortResolver(PortResolver portResolver) {
|
||||
this.portResolver = portResolver;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,6 @@
|
|||
|
||||
package org.acegisecurity.ui.logout;
|
||||
|
||||
import org.acegisecurity.Authentication;
|
||||
|
||||
import org.acegisecurity.context.SecurityContextHolder;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
@ -35,130 +26,163 @@ import javax.servlet.ServletResponse;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.acegisecurity.Authentication;
|
||||
import org.acegisecurity.context.SecurityContextHolder;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Logs a principal out.<p>Polls a series of {@link LogoutHandler}s. The handlers should be specified in the order
|
||||
* they are required. Generally you will want to call logout handlers <code>TokenBasedRememberMeServices</code> and
|
||||
* <code>SecurityContextLogoutHandler</code> (in that order).</p>
|
||||
* <p>After logout, the URL specified by {@link #logoutSuccessUrl} will be shown.</p>
|
||||
* <p><b>Do not use this class directly.</b> Instead configure <code>web.xml</code> to use the {@link
|
||||
* org.acegisecurity.util.FilterToBeanProxy}.</p>
|
||||
*
|
||||
* Logs a principal out.
|
||||
* <p>
|
||||
* Polls a series of {@link LogoutHandler}s. The handlers should be specified
|
||||
* in the order they are required. Generally you will want to call logout
|
||||
* handlers <code>TokenBasedRememberMeServices</code> and
|
||||
* <code>SecurityContextLogoutHandler</code> (in that order).
|
||||
* </p>
|
||||
* <p>
|
||||
* After logout, the URL specified by {@link #logoutSuccessUrl} will be shown.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Do not use this class directly.</b> Instead configure
|
||||
* <code>web.xml</code> to use the {@link
|
||||
* org.acegisecurity.util.FilterToBeanProxy}.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LogoutFilter implements Filter {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
public class LogoutFilter implements Filter, ApplicationContextAware {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(LogoutFilter.class);
|
||||
private static final Log logger = LogFactory.getLog(LogoutFilter.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private String filterProcessesUrl = "/j_acegi_logout";
|
||||
private String logoutSuccessUrl;
|
||||
private LogoutHandler[] handlers;
|
||||
private String filterProcessesUrl = "/j_acegi_logout";
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
private String logoutSuccessUrl;
|
||||
|
||||
public LogoutFilter(String logoutSuccessUrl, LogoutHandler[] handlers) {
|
||||
Assert.hasText(logoutSuccessUrl, "LogoutSuccessUrl required");
|
||||
Assert.notEmpty(handlers, "LogoutHandlers are required");
|
||||
this.logoutSuccessUrl = logoutSuccessUrl;
|
||||
this.handlers = handlers;
|
||||
}
|
||||
private LogoutHandler[] handlers;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* Not used. Use IoC container lifecycle methods instead.
|
||||
*/
|
||||
public void destroy() {}
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
if (!(request instanceof HttpServletRequest)) {
|
||||
throw new ServletException("Can only process HttpServletRequest");
|
||||
}
|
||||
public LogoutFilter(String logoutSuccessUrl, LogoutHandler[] handlers) {
|
||||
Assert.hasText(logoutSuccessUrl, "LogoutSuccessUrl required");
|
||||
Assert.notEmpty(handlers, "LogoutHandlers are required");
|
||||
this.logoutSuccessUrl = logoutSuccessUrl;
|
||||
this.handlers = handlers;
|
||||
}
|
||||
|
||||
if (!(response instanceof HttpServletResponse)) {
|
||||
throw new ServletException("Can only process HttpServletResponse");
|
||||
}
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
/**
|
||||
* Not used. Use IoC container lifecycle methods instead.
|
||||
*/
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
if (requiresLogout(httpRequest, httpResponse)) {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
|
||||
ServletException {
|
||||
if (!(request instanceof HttpServletRequest)) {
|
||||
throw new ServletException("Can only process HttpServletRequest");
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Logging out user '" + auth + "' and redirecting to logout page");
|
||||
}
|
||||
if (!(response instanceof HttpServletResponse)) {
|
||||
throw new ServletException("Can only process HttpServletResponse");
|
||||
}
|
||||
|
||||
for (int i = 0; i < handlers.length; i++) {
|
||||
handlers[i].logout(httpRequest, httpResponse, auth);
|
||||
}
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
|
||||
sendRedirect(httpRequest, httpResponse, logoutSuccessUrl);
|
||||
if (requiresLogout(httpRequest, httpResponse)) {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
return;
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Logging out user '" + auth + "' and redirecting to logout page");
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
for (int i = 0; i < handlers.length; i++) {
|
||||
handlers[i].logout(httpRequest, httpResponse, auth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not used. Use IoC container lifecycle methods instead.
|
||||
*
|
||||
* @param arg0 ignored
|
||||
*
|
||||
* @throws ServletException ignored
|
||||
*/
|
||||
public void init(FilterConfig arg0) throws ServletException {}
|
||||
sendRedirect(httpRequest, httpResponse, logoutSuccessUrl);
|
||||
|
||||
/**
|
||||
* Allow subclasses to modify when a logout should tak eplace.
|
||||
*
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
*
|
||||
* @return <code>true</code> if logout should occur, <code>false</code> otherwise
|
||||
*/
|
||||
protected boolean requiresLogout(HttpServletRequest request, HttpServletResponse response) {
|
||||
String uri = request.getRequestURI();
|
||||
int pathParamIndex = uri.indexOf(';');
|
||||
return;
|
||||
}
|
||||
|
||||
if (pathParamIndex > 0) {
|
||||
// strip everything after the first semi-colon
|
||||
uri = uri.substring(0, pathParamIndex);
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
if ("".equals(request.getContextPath())) {
|
||||
return uri.endsWith(filterProcessesUrl);
|
||||
}
|
||||
|
||||
return uri.endsWith(request.getContextPath() + filterProcessesUrl);
|
||||
}
|
||||
/**
|
||||
* Not used. Use IoC container lifecycle methods instead.
|
||||
*
|
||||
* @param arg0 ignored
|
||||
*
|
||||
* @throws ServletException ignored
|
||||
*/
|
||||
public void init(FilterConfig arg0) throws ServletException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow subclasses to modify the redirection message.
|
||||
*
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @param url the URL to redirect to
|
||||
*
|
||||
* @throws IOException in the event of any failure
|
||||
*/
|
||||
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
|
||||
throws IOException {
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
url = request.getContextPath() + url;
|
||||
}
|
||||
/**
|
||||
* Allow subclasses to modify when a logout should tak eplace.
|
||||
*
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
*
|
||||
* @return <code>true</code> if logout should occur, <code>false</code>
|
||||
* otherwise
|
||||
*/
|
||||
protected boolean requiresLogout(HttpServletRequest request, HttpServletResponse response) {
|
||||
String uri = request.getRequestURI();
|
||||
int pathParamIndex = uri.indexOf(';');
|
||||
|
||||
response.sendRedirect(response.encodeRedirectURL(url));
|
||||
}
|
||||
if (pathParamIndex > 0) {
|
||||
// strip everything after the first semi-colon
|
||||
uri = uri.substring(0, pathParamIndex);
|
||||
}
|
||||
|
||||
if ("".equals(request.getContextPath())) {
|
||||
return uri.endsWith(filterProcessesUrl);
|
||||
}
|
||||
|
||||
return uri.endsWith(request.getContextPath() + filterProcessesUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow subclasses to modify the redirection message.
|
||||
*
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @param url the URL to redirect to
|
||||
*
|
||||
* @throws IOException in the event of any failure
|
||||
*/
|
||||
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
|
||||
throws IOException {
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
url = request.getContextPath() + url;
|
||||
}
|
||||
|
||||
response.sendRedirect(response.encodeRedirectURL(url));
|
||||
}
|
||||
|
||||
public void setFilterProcessesUrl(String filterProcessesUrl) {
|
||||
Assert.hasText(filterProcessesUrl, "FilterProcessesUrl required");
|
||||
this.filterProcessesUrl = filterProcessesUrl;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public void setFilterProcessesUrl(String filterProcessesUrl) {
|
||||
Assert.hasText(filterProcessesUrl, "FilterProcessesUrl required");
|
||||
this.filterProcessesUrl = filterProcessesUrl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,9 @@ public class SecurityContextLogoutHandler implements LogoutHandler, Ordered {
|
|||
|
||||
private boolean invalidateHttpSession = true;
|
||||
|
||||
private int order = Integer.MAX_VALUE; //~ default
|
||||
private int DEFAULT_ORDER = Integer.MAX_VALUE; // ~ default
|
||||
|
||||
private int order = DEFAULT_ORDER;
|
||||
|
||||
/**
|
||||
* Requires the request to be passed in.
|
||||
|
|
|
@ -26,14 +26,18 @@ import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEv
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
|
@ -64,7 +68,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class RememberMeProcessingFilter implements Filter, InitializingBean, ApplicationEventPublisherAware {
|
||||
public class RememberMeProcessingFilter implements Filter, InitializingBean, ApplicationEventPublisherAware, ApplicationContextAware {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(RememberMeProcessingFilter.class);
|
||||
|
@ -75,12 +79,59 @@ public class RememberMeProcessingFilter implements Filter, InitializingBean, App
|
|||
private AuthenticationManager authenticationManager;
|
||||
private RememberMeServices rememberMeServices = new NullRememberMeServices();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private boolean isSetAuthenticationManagerInvoked = false;
|
||||
|
||||
private boolean isSetRememberMeServicesInvoked = false;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(rememberMeServices, "RememberMeServices required");
|
||||
Assert.notNull(authenticationManager, "AuthenticationManager required");
|
||||
}
|
||||
if (!isSetAuthenticationManagerInvoked) {
|
||||
autoDetectAuthenticationManager();
|
||||
}
|
||||
if (!isSetRememberMeServicesInvoked ) {
|
||||
autoDetectRememberMeServices();
|
||||
}
|
||||
Assert.notNull(authenticationManager, "authenticationManager must be specified");
|
||||
Assert.notNull(this.rememberMeServices);
|
||||
}
|
||||
|
||||
private void autoDetectRememberMeServices() {
|
||||
if (applicationContext != null) {
|
||||
Map map = applicationContext.getBeansOfType(RememberMeServices.class);
|
||||
if (map.size() > 0) {
|
||||
setRememberMeServices((RememberMeServices) map.values().iterator().next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Introspects the <code>Applicationcontext</code> for the single instance
|
||||
* of <code>AuthenticationManager</code>. If found invoke
|
||||
* setAuthenticationManager method by providing the found instance of
|
||||
* authenticationManager as a method parameter. If more than one instance of
|
||||
* <code>AuthenticationManager</code> is found, the method throws
|
||||
* <code>IllegalStateException</code>.
|
||||
*
|
||||
* @param applicationContext to locate the instance
|
||||
*/
|
||||
private void autoDetectAuthenticationManager() {
|
||||
if (applicationContext != null) {
|
||||
Map map = applicationContext.getBeansOfType(AuthenticationManager.class);
|
||||
if (map.size() > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"More than one AuthenticationManager beans detected please refer to the one using "
|
||||
+ " [ authenticationManager ] " + "property");
|
||||
}
|
||||
else if (map.size() == 1) {
|
||||
setAuthenticationManager((AuthenticationManager) map.values().iterator().next());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does nothing - we rely on IoC lifecycle services instead.
|
||||
|
@ -167,4 +218,9 @@ public class RememberMeProcessingFilter implements Filter, InitializingBean, App
|
|||
public void setRememberMeServices(RememberMeServices rememberMeServices) {
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext=applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.acegisecurity.ui.rememberme;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -23,6 +24,8 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.acegisecurity.Authentication;
|
||||
import org.acegisecurity.providers.rememberme.RememberMeAuthenticationToken;
|
||||
import org.acegisecurity.ui.AccessDeniedHandler;
|
||||
import org.acegisecurity.ui.AccessDeniedHandlerImpl;
|
||||
import org.acegisecurity.ui.AuthenticationDetailsSource;
|
||||
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
|
||||
import org.acegisecurity.ui.logout.LogoutHandler;
|
||||
|
@ -33,337 +36,419 @@ import org.apache.commons.codec.binary.Base64;
|
|||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.RequestUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Identifies previously remembered users by a Base-64 encoded cookie.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This implementation does not rely on an external database, so is attractive for simple applications.
|
||||
* The cookie will be valid for a specific period from the date of the last
|
||||
* {@link #loginSuccess(HttpServletRequest, HttpServletResponse, Authentication)}. As per the
|
||||
* interface contract, this method will only be called when the principal completes a successful interactive
|
||||
* authentication. As such the time period commences from the last authentication attempt where they furnished
|
||||
* credentials - not the time period they last logged in via remember-me. The implementation will only send a
|
||||
* remember-me token if the parameter defined by {@link #setParameter(String)} is present.</p>
|
||||
*
|
||||
* <p>An {@link org.acegisecurity.userdetails.UserDetailsService} is required by this implementation, so that it
|
||||
* can construct a valid <code>Authentication</code> from the returned {@link
|
||||
* org.acegisecurity.userdetails.UserDetails}. This is also necessary so that the user's password is available and can
|
||||
* be checked as part of the encoded cookie.</p>
|
||||
*
|
||||
* This implementation does not rely on an external database, so is attractive
|
||||
* for simple applications. The cookie will be valid for a specific period from
|
||||
* the date of the last
|
||||
* {@link #loginSuccess(HttpServletRequest, HttpServletResponse, Authentication)}.
|
||||
* As per the interface contract, this method will only be called when the
|
||||
* principal completes a successful interactive authentication. As such the time
|
||||
* period commences from the last authentication attempt where they furnished
|
||||
* credentials - not the time period they last logged in via remember-me. The
|
||||
* implementation will only send a remember-me token if the parameter defined by
|
||||
* {@link #setParameter(String)} is present.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* An {@link org.acegisecurity.userdetails.UserDetailsService} is required by
|
||||
* this implementation, so that it can construct a valid
|
||||
* <code>Authentication</code> from the returned {@link
|
||||
* org.acegisecurity.userdetails.UserDetails}. This is also necessary so that
|
||||
* the user's password is available and can be checked as part of the encoded
|
||||
* cookie.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The cookie encoded by this implementation adopts the following form:
|
||||
* <pre>username + ":" + expiryTime + ":" + Md5Hex(username + ":" + expiryTime + ":" + password + ":" + key)</pre>
|
||||
*
|
||||
* <pre>
|
||||
* username + ":" + expiryTime + ":" + Md5Hex(username + ":" + expiryTime + ":" + password + ":" + key)
|
||||
* </pre>
|
||||
*
|
||||
* </p>
|
||||
* <p>
|
||||
* As such, if the user changes their password any remember-me token will be invalidated. Equally, the system
|
||||
* administrator may invalidate every remember-me token on issue by changing the key. This provides some reasonable
|
||||
* approaches to recovering from a remember-me token being left on a public machine (eg kiosk system, Internet cafe
|
||||
* etc). Most importantly, at no time is the user's password ever sent to the user agent, providing an important
|
||||
* security safeguard. Unfortunately the username is necessary in this implementation (as we do not want to rely on a
|
||||
* database for remember-me services) and as such high security applications should be aware of this occasionally
|
||||
* undesired disclosure of a valid username.
|
||||
* As such, if the user changes their password any remember-me token will be
|
||||
* invalidated. Equally, the system administrator may invalidate every
|
||||
* remember-me token on issue by changing the key. This provides some reasonable
|
||||
* approaches to recovering from a remember-me token being left on a public
|
||||
* machine (eg kiosk system, Internet cafe etc). Most importantly, at no time is
|
||||
* the user's password ever sent to the user agent, providing an important
|
||||
* security safeguard. Unfortunately the username is necessary in this
|
||||
* implementation (as we do not want to rely on a database for remember-me
|
||||
* services) and as such high security applications should be aware of this
|
||||
* occasionally undesired disclosure of a valid username.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is a basic remember-me implementation which is suitable for many applications. However, we recommend a
|
||||
* database-based implementation if you require a more secure remember-me approach.
|
||||
* This is a basic remember-me implementation which is suitable for many
|
||||
* applications. However, we recommend a database-based implementation if you
|
||||
* require a more secure remember-me approach.
|
||||
* </p>
|
||||
* <p>
|
||||
* By default the tokens will be valid for 14 days from the last successful authentication attempt. This can be
|
||||
* changed using {@link #setTokenValiditySeconds(long)}.
|
||||
* By default the tokens will be valid for 14 days from the last successful
|
||||
* authentication attempt. This can be changed using
|
||||
* {@link #setTokenValiditySeconds(long)}.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @version $Id: TokenBasedRememberMeServices.java 1871 2007-05-25 03:12:49Z
|
||||
* benalex $
|
||||
*/
|
||||
public class TokenBasedRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler, Ordered {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
public class TokenBasedRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler, Ordered, ApplicationContextAware {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
public static final String ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY = "ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE";
|
||||
public static final String DEFAULT_PARAMETER = "_acegi_security_remember_me";
|
||||
protected static final Log logger = LogFactory.getLog(TokenBasedRememberMeServices.class);
|
||||
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
public static final String ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY = "ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE";
|
||||
|
||||
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||
private String key;
|
||||
private String parameter = DEFAULT_PARAMETER;
|
||||
private UserDetailsService userDetailsService;
|
||||
private long tokenValiditySeconds = 1209600; // 14 days
|
||||
private boolean alwaysRemember = false;
|
||||
private int order = Integer.MAX_VALUE; //~ default
|
||||
private String cookieName = ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY;
|
||||
public static final String DEFAULT_PARAMETER = "_acegi_security_remember_me";
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
protected static final Log logger = LogFactory.getLog(TokenBasedRememberMeServices.class);
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(key);
|
||||
Assert.hasLength(parameter);
|
||||
Assert.hasLength(cookieName);
|
||||
Assert.notNull(userDetailsService);
|
||||
}
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
|
||||
|
||||
if ((cookies == null) || (cookies.length == 0)) {
|
||||
return null;
|
||||
}
|
||||
private String key;
|
||||
|
||||
for (int i = 0; i < cookies.length; i++) {
|
||||
if (cookieName.equals(cookies[i].getName())) {
|
||||
String cookieValue = cookies[i].getValue();
|
||||
private String parameter = DEFAULT_PARAMETER;
|
||||
|
||||
for (int j = 0; j < cookieValue.length() % 4; j++) {
|
||||
cookieValue = cookieValue + "=";
|
||||
}
|
||||
|
||||
if (Base64.isArrayByteBase64(cookieValue.getBytes())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Remember-me cookie detected");
|
||||
}
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
// Decode token from Base64
|
||||
// format of token is:
|
||||
// username + ":" + expiryTime + ":" +
|
||||
// Md5Hex(username + ":" + expiryTime + ":" + password + ":" + key)
|
||||
String cookieAsPlainText = new String(Base64.decodeBase64(cookieValue.getBytes()));
|
||||
String[] cookieTokens = StringUtils.delimitedListToStringArray(cookieAsPlainText, ":");
|
||||
private long tokenValiditySeconds = 1209600; // 14 days
|
||||
|
||||
if (cookieTokens.length == 3) {
|
||||
long tokenExpiryTime;
|
||||
private boolean alwaysRemember = false;
|
||||
|
||||
try {
|
||||
tokenExpiryTime = new Long(cookieTokens[1]).longValue();
|
||||
} catch (NumberFormatException nfe) {
|
||||
cancelCookie(request, response,
|
||||
"Cookie token[1] did not contain a valid number (contained '" + cookieTokens[1] + "')");
|
||||
private static final int DEFAULT_ORDER = Integer.MAX_VALUE; // ~ default
|
||||
|
||||
return null;
|
||||
}
|
||||
private int order = DEFAULT_ORDER;
|
||||
|
||||
// Check it has not expired
|
||||
if (tokenExpiryTime < System.currentTimeMillis()) {
|
||||
cancelCookie(request, response,
|
||||
"Cookie token[1] has expired (expired on '" + new Date(tokenExpiryTime)
|
||||
+ "'; current time is '" + new Date() + "')");
|
||||
private String cookieName = ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY;
|
||||
|
||||
return null;
|
||||
}
|
||||
private boolean isSetUserDetailsServiceInvoked = false;
|
||||
|
||||
// Check the user exists
|
||||
// Defer lookup until after expiry time checked, to possibly avoid expensive lookup
|
||||
UserDetails userDetails;
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
try {
|
||||
userDetails = this.userDetailsService.loadUserByUsername(cookieTokens[0]);
|
||||
} catch (UsernameNotFoundException notFound) {
|
||||
cancelCookie(request, response,
|
||||
"Cookie token[0] contained username '" + cookieTokens[0] + "' but was not found");
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
return null;
|
||||
}
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(key);
|
||||
Assert.hasLength(parameter);
|
||||
Assert.hasLength(cookieName);
|
||||
Assert.notNull(applicationContext, "ApplicationContext required");
|
||||
if (!isSetUserDetailsServiceInvoked) {
|
||||
autoDetectAnyUserDetailsServiceAndUseIt(applicationContext);
|
||||
}
|
||||
Assert.notNull(userDetailsService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Introspects the <code>Applicationcontext</code> for the single instance
|
||||
* of {@link AccessDeniedHandler}. If found invoke
|
||||
* setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) method by
|
||||
* providing the found instance of accessDeniedHandler as a method
|
||||
* parameter. If more than one instance of <code>AccessDeniedHandler</code>
|
||||
* is found, the method throws <code>IllegalStateException</code>.
|
||||
*
|
||||
* @param applicationContext to locate the instance
|
||||
*/
|
||||
private void autoDetectAnyUserDetailsServiceAndUseIt(ApplicationContext applicationContext) {
|
||||
Map map = applicationContext.getBeansOfType(UserDetailsService.class);
|
||||
if (map.size() > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"More than one UserDetailsService beans detected please refer to the one using "
|
||||
+ " [ principalRepositoryBeanRef ] " + "attribute");
|
||||
}
|
||||
else if (map.size() == 1) {
|
||||
setUserDetailsService((UserDetailsService) map.values().iterator().next());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Immediately reject if the user is not allowed to login
|
||||
if (!userDetails.isAccountNonExpired() || !userDetails.isCredentialsNonExpired()
|
||||
|| !userDetails.isEnabled()) {
|
||||
cancelCookie(request, response,
|
||||
"Cookie token[0] contained username '" + cookieTokens[0]
|
||||
+ "' but account has expired, credentials have expired, or user is disabled");
|
||||
public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
|
||||
return null;
|
||||
}
|
||||
if ((cookies == null) || (cookies.length == 0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check signature of token matches remaining details
|
||||
// Must do this after user lookup, as we need the DAO-derived password
|
||||
// If efficiency was a major issue, just add in a UserCache implementation,
|
||||
// but recall this method is usually only called one per HttpSession
|
||||
// (as if the token is valid, it will cause SecurityContextHolder population, whilst
|
||||
// if invalid, will cause the cookie to be cancelled)
|
||||
String expectedTokenSignature = DigestUtils.md5Hex(userDetails.getUsername() + ":"
|
||||
+ tokenExpiryTime + ":" + userDetails.getPassword() + ":" + this.key);
|
||||
for (int i = 0; i < cookies.length; i++) {
|
||||
if (cookieName.equals(cookies[i].getName())) {
|
||||
String cookieValue = cookies[i].getValue();
|
||||
|
||||
if (!expectedTokenSignature.equals(cookieTokens[2])) {
|
||||
cancelCookie(request, response,
|
||||
"Cookie token[2] contained signature '" + cookieTokens[2] + "' but expected '"
|
||||
+ expectedTokenSignature + "'");
|
||||
for (int j = 0; j < cookieValue.length() % 4; j++) {
|
||||
cookieValue = cookieValue + "=";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
if (Base64.isArrayByteBase64(cookieValue.getBytes())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Remember-me cookie detected");
|
||||
}
|
||||
|
||||
// By this stage we have a valid token
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Remember-me cookie accepted");
|
||||
}
|
||||
// Decode token from Base64
|
||||
// format of token is:
|
||||
// username + ":" + expiryTime + ":" +
|
||||
// Md5Hex(username + ":" + expiryTime + ":" + password + ":"
|
||||
// + key)
|
||||
String cookieAsPlainText = new String(Base64.decodeBase64(cookieValue.getBytes()));
|
||||
String[] cookieTokens = StringUtils.delimitedListToStringArray(cookieAsPlainText, ":");
|
||||
|
||||
RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken(this.key, userDetails,
|
||||
userDetails.getAuthorities());
|
||||
auth.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
|
||||
if (cookieTokens.length == 3) {
|
||||
long tokenExpiryTime;
|
||||
|
||||
return auth;
|
||||
} else {
|
||||
cancelCookie(request, response,
|
||||
"Cookie token did not contain 3 tokens; decoded value was '" + cookieAsPlainText + "'");
|
||||
try {
|
||||
tokenExpiryTime = new Long(cookieTokens[1]).longValue();
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
cancelCookie(request, response,
|
||||
"Cookie token[1] did not contain a valid number (contained '" + cookieTokens[1]
|
||||
+ "')");
|
||||
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
cancelCookie(request, response,
|
||||
"Cookie token was not Base64 encoded; value was '" + cookieValue + "'");
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check it has not expired
|
||||
if (tokenExpiryTime < System.currentTimeMillis()) {
|
||||
cancelCookie(request, response, "Cookie token[1] has expired (expired on '"
|
||||
+ new Date(tokenExpiryTime) + "'; current time is '" + new Date() + "')");
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void cancelCookie(HttpServletRequest request, HttpServletResponse response, String reasonForLog) {
|
||||
if ((reasonForLog != null) && logger.isDebugEnabled()) {
|
||||
logger.debug("Cancelling cookie for reason: " + reasonForLog);
|
||||
}
|
||||
// Check the user exists
|
||||
// Defer lookup until after expiry time checked, to
|
||||
// possibly avoid expensive lookup
|
||||
UserDetails userDetails;
|
||||
|
||||
response.addCookie(makeCancelCookie(request));
|
||||
}
|
||||
try {
|
||||
userDetails = this.userDetailsService.loadUserByUsername(cookieTokens[0]);
|
||||
}
|
||||
catch (UsernameNotFoundException notFound) {
|
||||
cancelCookie(request, response, "Cookie token[0] contained username '" + cookieTokens[0]
|
||||
+ "' but was not found");
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getParameter() {
|
||||
return parameter;
|
||||
}
|
||||
// Immediately reject if the user is not allowed to
|
||||
// login
|
||||
if (!userDetails.isAccountNonExpired() || !userDetails.isCredentialsNonExpired()
|
||||
|| !userDetails.isEnabled()) {
|
||||
cancelCookie(request, response, "Cookie token[0] contained username '" + cookieTokens[0]
|
||||
+ "' but account has expired, credentials have expired, or user is disabled");
|
||||
|
||||
public long getTokenValiditySeconds() {
|
||||
return tokenValiditySeconds;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public UserDetailsService getUserDetailsService() {
|
||||
return userDetailsService;
|
||||
}
|
||||
// Check signature of token matches remaining details
|
||||
// Must do this after user lookup, as we need the
|
||||
// DAO-derived password
|
||||
// If efficiency was a major issue, just add in a
|
||||
// UserCache implementation,
|
||||
// but recall this method is usually only called one per
|
||||
// HttpSession
|
||||
// (as if the token is valid, it will cause
|
||||
// SecurityContextHolder population, whilst
|
||||
// if invalid, will cause the cookie to be cancelled)
|
||||
String expectedTokenSignature = DigestUtils.md5Hex(userDetails.getUsername() + ":"
|
||||
+ tokenExpiryTime + ":" + userDetails.getPassword() + ":" + this.key);
|
||||
|
||||
public void loginFail(HttpServletRequest request, HttpServletResponse response) {
|
||||
cancelCookie(request, response, "Interactive authentication attempt was unsuccessful");
|
||||
}
|
||||
if (!expectedTokenSignature.equals(cookieTokens[2])) {
|
||||
cancelCookie(request, response, "Cookie token[2] contained signature '" + cookieTokens[2]
|
||||
+ "' but expected '" + expectedTokenSignature + "'");
|
||||
|
||||
protected boolean rememberMeRequested(HttpServletRequest request, String parameter) {
|
||||
if (alwaysRemember) {
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return RequestUtils.getBooleanParameter(request, parameter, false);
|
||||
}
|
||||
// By this stage we have a valid token
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Remember-me cookie accepted");
|
||||
}
|
||||
|
||||
public void loginSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication successfulAuthentication) {
|
||||
// Exit if the principal hasn't asked to be remembered
|
||||
if (!rememberMeRequested(request, parameter)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Did not send remember-me cookie (principal did not set parameter '" + this.parameter
|
||||
+ "')");
|
||||
}
|
||||
RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken(this.key, userDetails,
|
||||
userDetails.getAuthorities());
|
||||
auth.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
|
||||
|
||||
return;
|
||||
}
|
||||
return auth;
|
||||
}
|
||||
else {
|
||||
cancelCookie(request, response, "Cookie token did not contain 3 tokens; decoded value was '"
|
||||
+ cookieAsPlainText + "'");
|
||||
|
||||
// Determine username and password, ensuring empty strings
|
||||
Assert.notNull(successfulAuthentication.getPrincipal());
|
||||
Assert.notNull(successfulAuthentication.getCredentials());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cancelCookie(request, response, "Cookie token was not Base64 encoded; value was '" + cookieValue
|
||||
+ "'");
|
||||
|
||||
String username;
|
||||
String password;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (successfulAuthentication.getPrincipal() instanceof UserDetails) {
|
||||
username = ((UserDetails) successfulAuthentication.getPrincipal()).getUsername();
|
||||
password = ((UserDetails) successfulAuthentication.getPrincipal()).getPassword();
|
||||
} else {
|
||||
username = successfulAuthentication.getPrincipal().toString();
|
||||
password = successfulAuthentication.getCredentials().toString();
|
||||
}
|
||||
|
||||
// If unable to find a username and password, just abort as TokenBasedRememberMeServices unable to construct a valid token in this case
|
||||
if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
|
||||
return;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.hasLength(username);
|
||||
Assert.hasLength(password);
|
||||
private void cancelCookie(HttpServletRequest request, HttpServletResponse response, String reasonForLog) {
|
||||
if ((reasonForLog != null) && logger.isDebugEnabled()) {
|
||||
logger.debug("Cancelling cookie for reason: " + reasonForLog);
|
||||
}
|
||||
|
||||
long expiryTime = System.currentTimeMillis() + (tokenValiditySeconds * 1000);
|
||||
response.addCookie(makeCancelCookie(request));
|
||||
}
|
||||
|
||||
// construct token to put in cookie; format is:
|
||||
// username + ":" + expiryTime + ":" + Md5Hex(username + ":" + expiryTime + ":" + password + ":" + key)
|
||||
String signatureValue = DigestUtils.md5Hex(username + ":" + expiryTime + ":" + password + ":" + key);
|
||||
String tokenValue = username + ":" + expiryTime + ":" + signatureValue;
|
||||
String tokenValueBase64 = new String(Base64.encodeBase64(tokenValue.getBytes()));
|
||||
response.addCookie(makeValidCookie(tokenValueBase64, request, tokenValiditySeconds));
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added remember-me cookie for user '" + username
|
||||
+ "', expiry: '" + new Date(expiryTime) + "'");
|
||||
}
|
||||
}
|
||||
public String getParameter() {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
|
||||
cancelCookie(request, response, "Logout of user "
|
||||
+ (authentication == null ? "Unknown" : authentication.getName()));
|
||||
}
|
||||
public long getTokenValiditySeconds() {
|
||||
return tokenValiditySeconds;
|
||||
}
|
||||
|
||||
protected Cookie makeCancelCookie(HttpServletRequest request) {
|
||||
Cookie cookie = new Cookie(cookieName, null);
|
||||
cookie.setMaxAge(0);
|
||||
cookie.setPath(StringUtils.hasLength(request.getContextPath()) ? request.getContextPath() : "/");
|
||||
public UserDetailsService getUserDetailsService() {
|
||||
return userDetailsService;
|
||||
}
|
||||
|
||||
return cookie;
|
||||
}
|
||||
public void loginFail(HttpServletRequest request, HttpServletResponse response) {
|
||||
cancelCookie(request, response, "Interactive authentication attempt was unsuccessful");
|
||||
}
|
||||
|
||||
protected Cookie makeValidCookie(String tokenValueBase64, HttpServletRequest request, long maxAge) {
|
||||
Cookie cookie = new Cookie(cookieName, tokenValueBase64);
|
||||
cookie.setMaxAge(new Long(maxAge).intValue());
|
||||
cookie.setPath(StringUtils.hasLength(request.getContextPath()) ? request.getContextPath() : "/");
|
||||
protected boolean rememberMeRequested(HttpServletRequest request, String parameter) {
|
||||
if (alwaysRemember) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return cookie;
|
||||
}
|
||||
return RequestUtils.getBooleanParameter(request, parameter, false);
|
||||
}
|
||||
|
||||
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
public void loginSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication successfulAuthentication) {
|
||||
// Exit if the principal hasn't asked to be remembered
|
||||
if (!rememberMeRequested(request, parameter)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Did not send remember-me cookie (principal did not set parameter '" + this.parameter
|
||||
+ "')");
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public void setParameter(String parameter) {
|
||||
this.parameter = parameter;
|
||||
}
|
||||
// Determine username and password, ensuring empty strings
|
||||
Assert.notNull(successfulAuthentication.getPrincipal());
|
||||
Assert.notNull(successfulAuthentication.getCredentials());
|
||||
|
||||
public void setCookieName(String cookieName) {
|
||||
String username;
|
||||
String password;
|
||||
|
||||
if (successfulAuthentication.getPrincipal() instanceof UserDetails) {
|
||||
username = ((UserDetails) successfulAuthentication.getPrincipal()).getUsername();
|
||||
password = ((UserDetails) successfulAuthentication.getPrincipal()).getPassword();
|
||||
}
|
||||
else {
|
||||
username = successfulAuthentication.getPrincipal().toString();
|
||||
password = successfulAuthentication.getCredentials().toString();
|
||||
}
|
||||
|
||||
// If unable to find a username and password, just abort as
|
||||
// TokenBasedRememberMeServices unable to construct a valid token in
|
||||
// this case
|
||||
if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.hasLength(username);
|
||||
Assert.hasLength(password);
|
||||
|
||||
long expiryTime = System.currentTimeMillis() + (tokenValiditySeconds * 1000);
|
||||
|
||||
// construct token to put in cookie; format is:
|
||||
// username + ":" + expiryTime + ":" + Md5Hex(username + ":" +
|
||||
// expiryTime + ":" + password + ":" + key)
|
||||
String signatureValue = DigestUtils.md5Hex(username + ":" + expiryTime + ":" + password + ":" + key);
|
||||
String tokenValue = username + ":" + expiryTime + ":" + signatureValue;
|
||||
String tokenValueBase64 = new String(Base64.encodeBase64(tokenValue.getBytes()));
|
||||
response.addCookie(makeValidCookie(tokenValueBase64, request, tokenValiditySeconds));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger
|
||||
.debug("Added remember-me cookie for user '" + username + "', expiry: '" + new Date(expiryTime)
|
||||
+ "'");
|
||||
}
|
||||
}
|
||||
|
||||
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
|
||||
cancelCookie(request, response, "Logout of user "
|
||||
+ (authentication == null ? "Unknown" : authentication.getName()));
|
||||
}
|
||||
|
||||
protected Cookie makeCancelCookie(HttpServletRequest request) {
|
||||
Cookie cookie = new Cookie(cookieName, null);
|
||||
cookie.setMaxAge(0);
|
||||
cookie.setPath(StringUtils.hasLength(request.getContextPath()) ? request.getContextPath() : "/");
|
||||
|
||||
return cookie;
|
||||
}
|
||||
|
||||
protected Cookie makeValidCookie(String tokenValueBase64, HttpServletRequest request, long maxAge) {
|
||||
Cookie cookie = new Cookie(cookieName, tokenValueBase64);
|
||||
cookie.setMaxAge(new Long(maxAge).intValue());
|
||||
cookie.setPath(StringUtils.hasLength(request.getContextPath()) ? request.getContextPath() : "/");
|
||||
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void setParameter(String parameter) {
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
public void setCookieName(String cookieName) {
|
||||
this.cookieName = cookieName;
|
||||
}
|
||||
|
||||
public void setTokenValiditySeconds(long tokenValiditySeconds) {
|
||||
this.tokenValiditySeconds = tokenValiditySeconds;
|
||||
}
|
||||
this.tokenValiditySeconds = tokenValiditySeconds;
|
||||
}
|
||||
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.isSetUserDetailsServiceInvoked = true;
|
||||
}
|
||||
|
||||
public boolean isAlwaysRemember() {
|
||||
return alwaysRemember;
|
||||
}
|
||||
public boolean isAlwaysRemember() {
|
||||
return alwaysRemember;
|
||||
}
|
||||
|
||||
public void setAlwaysRemember(boolean alwaysRemember) {
|
||||
this.alwaysRemember = alwaysRemember;
|
||||
}
|
||||
public void setAlwaysRemember(boolean alwaysRemember) {
|
||||
this.alwaysRemember = alwaysRemember;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
|
@ -373,4 +458,8 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
|
|||
this.order = order;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext=applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,206 +41,233 @@ import javax.servlet.ServletResponse;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Used by the <code>SecurityEnforcementFilter</code> to commence authentication via the {@link
|
||||
* AuthenticationProcessingFilter}. This object holds the location of the login form, relative to the web app context
|
||||
* path, and is used to commence a redirect to that form.</p>
|
||||
* <p>By setting the <em>forceHttps</em> property to true, you may configure the class to force the protocol used
|
||||
* for the login form to be <code>HTTPS</code>, even if the original intercepted request for a resource used the
|
||||
* <code>HTTP</code> protocol. When this happens, after a successful login (via HTTPS), the original resource will
|
||||
* still be accessed as HTTP, via the original request URL. For the forced HTTPS feature to work, the {@link
|
||||
* PortMapper} is consulted to determine the HTTP:HTTPS pairs.</p>
|
||||
*
|
||||
* <p>
|
||||
* Used by the <code>SecurityEnforcementFilter</code> to commence
|
||||
* authentication via the {@link AuthenticationProcessingFilter}. This object
|
||||
* holds the location of the login form, relative to the web app context path,
|
||||
* and is used to commence a redirect to that form.
|
||||
* </p>
|
||||
* <p>
|
||||
* By setting the <em>forceHttps</em> property to true, you may configure the
|
||||
* class to force the protocol used for the login form to be <code>HTTPS</code>,
|
||||
* even if the original intercepted request for a resource used the
|
||||
* <code>HTTP</code> protocol. When this happens, after a successful login
|
||||
* (via HTTPS), the original resource will still be accessed as HTTP, via the
|
||||
* original request URL. For the forced HTTPS feature to work, the {@link
|
||||
* PortMapper} is consulted to determine the HTTP:HTTPS pairs.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author colin sampaleanu
|
||||
* @author Omri Spector
|
||||
* @version $Id$
|
||||
* @version $Id: AuthenticationProcessingFilterEntryPoint.java 1873 2007-05-25
|
||||
* 03:21:17Z benalex $
|
||||
*/
|
||||
public class AuthenticationProcessingFilterEntryPoint implements AuthenticationEntryPoint, InitializingBean, Ordered {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AuthenticationProcessingFilterEntryPoint.class);
|
||||
private static final Log logger = LogFactory.getLog(AuthenticationProcessingFilterEntryPoint.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private PortMapper portMapper = new PortMapperImpl();
|
||||
private PortResolver portResolver = new PortResolverImpl();
|
||||
private String loginFormUrl;
|
||||
private boolean forceHttps = false;
|
||||
private boolean serverSideRedirect = false;
|
||||
private int order = Integer.MAX_VALUE; // ~ default
|
||||
private PortMapper portMapper = new PortMapperImpl();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
private PortResolver portResolver = new PortResolverImpl();
|
||||
|
||||
private String loginFormUrl;
|
||||
|
||||
private boolean forceHttps = false;
|
||||
|
||||
private boolean serverSideRedirect = false;
|
||||
|
||||
private int DEFAULT_ORDER = Integer.MAX_VALUE;// ~ default
|
||||
|
||||
private int order = DEFAULT_ORDER;
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(loginFormUrl, "loginFormUrl must be specified");
|
||||
Assert.notNull(portMapper, "portMapper must be specified");
|
||||
Assert.notNull(portResolver, "portResolver must be specified");
|
||||
}
|
||||
Assert.hasLength(loginFormUrl, "loginFormUrl must be specified");
|
||||
Assert.notNull(portMapper, "portMapper must be specified");
|
||||
Assert.notNull(portResolver, "portResolver must be specified");
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to modify the login form URL that should be applicable for a given request.
|
||||
* Allows subclasses to modify the login form URL that should be applicable
|
||||
* for a given request.
|
||||
*
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @param exception the exception
|
||||
* @return the URL (cannot be null or empty; defaults to {@link #getLoginFormUrl()})
|
||||
* @return the URL (cannot be null or empty; defaults to
|
||||
* {@link #getLoginFormUrl()})
|
||||
*/
|
||||
protected String determineUrlToUseForThisRequest(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) {
|
||||
protected String determineUrlToUseForThisRequest(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) {
|
||||
return getLoginFormUrl();
|
||||
}
|
||||
|
||||
public void commence(ServletRequest request, ServletResponse response, AuthenticationException authException)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
HttpServletResponse resp = (HttpServletResponse) response;
|
||||
String scheme = request.getScheme();
|
||||
String serverName = request.getServerName();
|
||||
int serverPort = portResolver.getServerPort(request);
|
||||
String contextPath = req.getContextPath();
|
||||
|
||||
boolean inHttp = "http".equals(scheme.toLowerCase());
|
||||
boolean inHttps = "https".equals(scheme.toLowerCase());
|
||||
public void commence(ServletRequest request, ServletResponse response, AuthenticationException authException)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
HttpServletResponse resp = (HttpServletResponse) response;
|
||||
String scheme = request.getScheme();
|
||||
String serverName = request.getServerName();
|
||||
int serverPort = portResolver.getServerPort(request);
|
||||
String contextPath = req.getContextPath();
|
||||
|
||||
boolean includePort = true;
|
||||
boolean inHttp = "http".equals(scheme.toLowerCase());
|
||||
boolean inHttps = "https".equals(scheme.toLowerCase());
|
||||
|
||||
String redirectUrl = null;
|
||||
boolean doForceHttps = false;
|
||||
Integer httpsPort = null;
|
||||
boolean includePort = true;
|
||||
|
||||
if (inHttp && (serverPort == 80)) {
|
||||
includePort = false;
|
||||
} else if (inHttps && (serverPort == 443)) {
|
||||
includePort = false;
|
||||
}
|
||||
String redirectUrl = null;
|
||||
boolean doForceHttps = false;
|
||||
Integer httpsPort = null;
|
||||
|
||||
if (forceHttps && inHttp) {
|
||||
httpsPort = (Integer) portMapper.lookupHttpsPort(new Integer(serverPort));
|
||||
|
||||
if (httpsPort != null) {
|
||||
doForceHttps = true;
|
||||
if (httpsPort.intValue() == 443) {
|
||||
includePort = false;
|
||||
} else {
|
||||
includePort = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
String loginForm = determineUrlToUseForThisRequest(req, resp, authException);
|
||||
|
||||
if ( serverSideRedirect ) {
|
||||
if (inHttp && (serverPort == 80)) {
|
||||
includePort = false;
|
||||
}
|
||||
else if (inHttps && (serverPort == 443)) {
|
||||
includePort = false;
|
||||
}
|
||||
|
||||
if ( doForceHttps ) {
|
||||
|
||||
// before doing server side redirect, we need to do client redirect to https.
|
||||
|
||||
String servletPath = req.getServletPath();
|
||||
String pathInfo = req.getPathInfo();
|
||||
String query = req.getQueryString();
|
||||
if (forceHttps && inHttp) {
|
||||
httpsPort = (Integer) portMapper.lookupHttpsPort(new Integer(serverPort));
|
||||
|
||||
redirectUrl = "https://" + serverName + ((includePort) ? (":" + httpsPort) : "") + contextPath
|
||||
+ servletPath + (pathInfo == null ? "" : pathInfo ) + (query == null ? "" : "?"+query );
|
||||
if (httpsPort != null) {
|
||||
doForceHttps = true;
|
||||
if (httpsPort.intValue() == 443) {
|
||||
includePort = false;
|
||||
}
|
||||
else {
|
||||
includePort = true;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Server side forward to: " + loginForm);
|
||||
}
|
||||
String loginForm = determineUrlToUseForThisRequest(req, resp, authException);
|
||||
|
||||
RequestDispatcher dispatcher = req.getRequestDispatcher(loginForm);
|
||||
if (serverSideRedirect) {
|
||||
|
||||
dispatcher.forward(request, response);
|
||||
|
||||
return;
|
||||
if (doForceHttps) {
|
||||
|
||||
}
|
||||
// before doing server side redirect, we need to do client
|
||||
// redirect to https.
|
||||
|
||||
} else {
|
||||
String servletPath = req.getServletPath();
|
||||
String pathInfo = req.getPathInfo();
|
||||
String query = req.getQueryString();
|
||||
|
||||
if ( doForceHttps ) {
|
||||
redirectUrl = "https://" + serverName + ((includePort) ? (":" + httpsPort) : "") + contextPath
|
||||
+ servletPath + (pathInfo == null ? "" : pathInfo) + (query == null ? "" : "?" + query);
|
||||
|
||||
redirectUrl = "https://" + serverName + ((includePort) ? (":" + httpsPort) : "") + contextPath
|
||||
+ loginForm;
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Server side forward to: " + loginForm);
|
||||
}
|
||||
|
||||
redirectUrl = scheme + "://" + serverName + ((includePort) ? (":" + serverPort) : "") + contextPath
|
||||
+ loginForm;
|
||||
RequestDispatcher dispatcher = req.getRequestDispatcher(loginForm);
|
||||
|
||||
}
|
||||
}
|
||||
dispatcher.forward(request, response);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Redirecting to: " + redirectUrl);
|
||||
}
|
||||
return;
|
||||
|
||||
((HttpServletResponse) response).sendRedirect(((HttpServletResponse) response).encodeRedirectURL(redirectUrl));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getForceHttps() {
|
||||
return forceHttps;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
public String getLoginFormUrl() {
|
||||
return loginFormUrl;
|
||||
}
|
||||
if (doForceHttps) {
|
||||
|
||||
public PortMapper getPortMapper() {
|
||||
return portMapper;
|
||||
}
|
||||
redirectUrl = "https://" + serverName + ((includePort) ? (":" + httpsPort) : "") + contextPath
|
||||
+ loginForm;
|
||||
|
||||
public PortResolver getPortResolver() {
|
||||
return portResolver;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
public boolean isServerSideRedirect() {
|
||||
return serverSideRedirect;
|
||||
}
|
||||
redirectUrl = scheme + "://" + serverName + ((includePort) ? (":" + serverPort) : "") + contextPath
|
||||
+ loginForm;
|
||||
|
||||
/**
|
||||
* Set to true to force login form access to be via https. If this value is ture (the default is false),
|
||||
* and the incoming request for the protected resource which triggered the interceptor was not already
|
||||
* <code>https</code>, then
|
||||
*
|
||||
* @param forceHttps
|
||||
*/
|
||||
public void setForceHttps(boolean forceHttps) {
|
||||
this.forceHttps = forceHttps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL where the <code>AuthenticationProcessingFilter</code> login page can be found. Should be
|
||||
* relative to the web-app context path, and include a leading <code>/</code>
|
||||
*
|
||||
* @param loginFormUrl
|
||||
*/
|
||||
public void setLoginFormUrl(String loginFormUrl) {
|
||||
this.loginFormUrl = loginFormUrl;
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Redirecting to: " + redirectUrl);
|
||||
}
|
||||
|
||||
public void setPortMapper(PortMapper portMapper) {
|
||||
this.portMapper = portMapper;
|
||||
}
|
||||
((HttpServletResponse) response).sendRedirect(((HttpServletResponse) response).encodeRedirectURL(redirectUrl));
|
||||
}
|
||||
|
||||
public void setPortResolver(PortResolver portResolver) {
|
||||
this.portResolver = portResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if we are to do a server side include of the <code>loginFormUrl</code> instead of a 302
|
||||
* redirect.
|
||||
*
|
||||
* @param serverSideRedirect
|
||||
*/
|
||||
public void setServerSideRedirect(boolean serverSideRedirect) {
|
||||
this.serverSideRedirect = serverSideRedirect;
|
||||
}
|
||||
|
||||
public boolean getForceHttps() {
|
||||
return forceHttps;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
public String getLoginFormUrl() {
|
||||
return loginFormUrl;
|
||||
}
|
||||
|
||||
public PortMapper getPortMapper() {
|
||||
return portMapper;
|
||||
}
|
||||
|
||||
public PortResolver getPortResolver() {
|
||||
return portResolver;
|
||||
}
|
||||
|
||||
public boolean isServerSideRedirect() {
|
||||
return serverSideRedirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to force login form access to be via https. If this value is
|
||||
* ture (the default is false), and the incoming request for the protected
|
||||
* resource which triggered the interceptor was not already
|
||||
* <code>https</code>, then
|
||||
*
|
||||
* @param forceHttps
|
||||
*/
|
||||
public void setForceHttps(boolean forceHttps) {
|
||||
this.forceHttps = forceHttps;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL where the <code>AuthenticationProcessingFilter</code> login
|
||||
* page can be found. Should be relative to the web-app context path, and
|
||||
* include a leading <code>/</code>
|
||||
*
|
||||
* @param loginFormUrl
|
||||
*/
|
||||
public void setLoginFormUrl(String loginFormUrl) {
|
||||
this.loginFormUrl = loginFormUrl;
|
||||
}
|
||||
|
||||
public void setPortMapper(PortMapper portMapper) {
|
||||
this.portMapper = portMapper;
|
||||
}
|
||||
|
||||
public void setPortResolver(PortResolver portResolver) {
|
||||
this.portResolver = portResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if we are to do a server side include of the
|
||||
* <code>loginFormUrl</code> instead of a 302 redirect.
|
||||
*
|
||||
* @param serverSideRedirect
|
||||
*/
|
||||
public void setServerSideRedirect(boolean serverSideRedirect) {
|
||||
this.serverSideRedirect = serverSideRedirect;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,300 +38,325 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link ExceptionTranslationFilter}.
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @version $Id: ExceptionTranslationFilterTests.java 1496 2006-05-23 13:38:33Z
|
||||
* benalex $
|
||||
*/
|
||||
public class ExceptionTranslationFilterTests extends TestCase {
|
||||
//~ Constructors ===================================================================================================
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public ExceptionTranslationFilterTests() {
|
||||
super();
|
||||
}
|
||||
public ExceptionTranslationFilterTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ExceptionTranslationFilterTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
public ExceptionTranslationFilterTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(ExceptionTranslationFilterTests.class);
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(ExceptionTranslationFilterTests.class);
|
||||
}
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public void testAccessDeniedWhenAnonymous() throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure/page.html");
|
||||
request.setServerPort(80);
|
||||
request.setScheme("http");
|
||||
request.setServerName("www.example.com");
|
||||
request.setContextPath("/mycontext");
|
||||
request.setRequestURI("/mycontext/secure/page.html");
|
||||
public void testAccessDeniedWhenAnonymous() throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure/page.html");
|
||||
request.setServerPort(80);
|
||||
request.setScheme("http");
|
||||
request.setServerName("www.example.com");
|
||||
request.setContextPath("/mycontext");
|
||||
request.setRequestURI("/mycontext/secure/page.html");
|
||||
|
||||
// Setup the FilterChain to thrown an access denied exception
|
||||
MockFilterChain chain = new MockFilterChain(true, false, false, false);
|
||||
// Setup the FilterChain to thrown an access denied exception
|
||||
MockFilterChain chain = new MockFilterChain(true, false, false, false);
|
||||
|
||||
// Setup SecurityContextHolder, as filter needs to check if user is anonymous
|
||||
SecurityContextHolder.getContext()
|
||||
.setAuthentication(new AnonymousAuthenticationToken("ignored", "ignored",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("IGNORED")}));
|
||||
// Setup SecurityContextHolder, as filter needs to check if user is
|
||||
// anonymous
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new AnonymousAuthenticationToken("ignored", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("IGNORED") }));
|
||||
|
||||
// Test
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
// Test
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, chain);
|
||||
assertEquals("/mycontext/login.jsp", response.getRedirectedUrl());
|
||||
assertEquals("http://www.example.com/mycontext/secure/page.html",
|
||||
AbstractProcessingFilter.obtainFullRequestUrl(request));
|
||||
}
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, chain);
|
||||
assertEquals("/mycontext/login.jsp", response.getRedirectedUrl());
|
||||
assertEquals("http://www.example.com/mycontext/secure/page.html", AbstractProcessingFilter
|
||||
.obtainFullRequestUrl(request));
|
||||
}
|
||||
|
||||
public void testAccessDeniedWhenNonAnonymous() throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure/page.html");
|
||||
public void testAccessDeniedWhenNonAnonymous() throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure/page.html");
|
||||
|
||||
// Setup the FilterChain to thrown an access denied exception
|
||||
MockFilterChain chain = new MockFilterChain(true, false, false, false);
|
||||
// Setup the FilterChain to thrown an access denied exception
|
||||
MockFilterChain chain = new MockFilterChain(true, false, false, false);
|
||||
|
||||
// Setup SecurityContextHolder, as filter needs to check if user is anonymous
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
// Setup SecurityContextHolder, as filter needs to check if user is
|
||||
// anonymous
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
|
||||
// Setup a new AccessDeniedHandlerImpl that will do a "forward"
|
||||
AccessDeniedHandlerImpl adh = new AccessDeniedHandlerImpl();
|
||||
adh.setErrorPage("/error.jsp");
|
||||
// Setup a new AccessDeniedHandlerImpl that will do a "forward"
|
||||
AccessDeniedHandlerImpl adh = new AccessDeniedHandlerImpl();
|
||||
adh.setErrorPage("/error.jsp");
|
||||
|
||||
// Test
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
filter.setAccessDeniedHandler(adh);
|
||||
// Test
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
filter.setAccessDeniedHandler(adh);
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, chain);
|
||||
assertEquals(403, response.getStatus());
|
||||
assertEquals(AccessDeniedException.class,
|
||||
request.getAttribute(AccessDeniedHandlerImpl.ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY).getClass());
|
||||
}
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, chain);
|
||||
assertEquals(403, response.getStatus());
|
||||
assertEquals(AccessDeniedException.class, request.getAttribute(
|
||||
AccessDeniedHandlerImpl.ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY).getClass());
|
||||
}
|
||||
|
||||
public void testDoFilterWithNonHttpServletRequestDetected()
|
||||
throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
public void testDoFilterWithNonHttpServletRequestDetected() throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
|
||||
try {
|
||||
filter.doFilter(null, new MockHttpServletResponse(), new MockFilterChain(false, false, false, false));
|
||||
fail("Should have thrown ServletException");
|
||||
} catch (ServletException expected) {
|
||||
assertEquals("HttpServletRequest required", expected.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
filter.doFilter(null, new MockHttpServletResponse(), new MockFilterChain(false, false, false, false));
|
||||
fail("Should have thrown ServletException");
|
||||
}
|
||||
catch (ServletException expected) {
|
||||
assertEquals("HttpServletRequest required", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testDoFilterWithNonHttpServletResponseDetected()
|
||||
throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
public void testDoFilterWithNonHttpServletResponseDetected() throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
|
||||
try {
|
||||
filter.doFilter(new MockHttpServletRequest(null, null), null,
|
||||
new MockFilterChain(false, false, false, false));
|
||||
fail("Should have thrown ServletException");
|
||||
} catch (ServletException expected) {
|
||||
assertEquals("HttpServletResponse required", expected.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
filter.doFilter(new MockHttpServletRequest(null, null), null, new MockFilterChain(false, false, false,
|
||||
false));
|
||||
fail("Should have thrown ServletException");
|
||||
}
|
||||
catch (ServletException expected) {
|
||||
assertEquals("HttpServletResponse required", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testGettersSetters() {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
public void testGettersSetters() {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
assertTrue(filter.getAuthenticationEntryPoint() != null);
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
assertTrue(filter.getAuthenticationEntryPoint() != null);
|
||||
|
||||
filter.setPortResolver(new MockPortResolver(80, 443));
|
||||
assertTrue(filter.getPortResolver() != null);
|
||||
}
|
||||
filter.setPortResolver(new MockPortResolver(80, 443));
|
||||
assertTrue(filter.getPortResolver() != null);
|
||||
}
|
||||
|
||||
public void testRedirectedToLoginFormAndSessionShowsOriginalTargetWhenAuthenticationException()
|
||||
throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure/page.html");
|
||||
request.setServerPort(80);
|
||||
request.setScheme("http");
|
||||
request.setServerName("www.example.com");
|
||||
request.setContextPath("/mycontext");
|
||||
request.setRequestURI("/mycontext/secure/page.html");
|
||||
public void testRedirectedToLoginFormAndSessionShowsOriginalTargetWhenAuthenticationException() throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure/page.html");
|
||||
request.setServerPort(80);
|
||||
request.setScheme("http");
|
||||
request.setServerName("www.example.com");
|
||||
request.setContextPath("/mycontext");
|
||||
request.setRequestURI("/mycontext/secure/page.html");
|
||||
|
||||
// Setup the FilterChain to thrown an authentication failure exception
|
||||
MockFilterChain chain = new MockFilterChain(false, true, false, false);
|
||||
// Setup the FilterChain to thrown an authentication failure exception
|
||||
MockFilterChain chain = new MockFilterChain(false, true, false, false);
|
||||
|
||||
// Test
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
filter.setPortResolver(new MockPortResolver(80, 443));
|
||||
filter.afterPropertiesSet();
|
||||
// Test
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
filter.setPortResolver(new MockPortResolver(80, 443));
|
||||
/*
|
||||
* Disabled the call to afterPropertiesSet as it requires
|
||||
* applicationContext to be injected before it is invoked. We do not
|
||||
* have this filter configured in IOC for this test hence no
|
||||
* ApplicationContext
|
||||
*/
|
||||
// filter.afterPropertiesSet();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, chain);
|
||||
assertEquals("/mycontext/login.jsp", response.getRedirectedUrl());
|
||||
assertEquals("http://www.example.com/mycontext/secure/page.html", AbstractProcessingFilter
|
||||
.obtainFullRequestUrl(request));
|
||||
}
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, chain);
|
||||
assertEquals("/mycontext/login.jsp", response.getRedirectedUrl());
|
||||
assertEquals("http://www.example.com/mycontext/secure/page.html",
|
||||
AbstractProcessingFilter.obtainFullRequestUrl(request));
|
||||
}
|
||||
public void testRedirectedToLoginFormAndSessionShowsOriginalTargetWithExoticPortWhenAuthenticationException()
|
||||
throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure/page.html");
|
||||
request.setServerPort(8080);
|
||||
request.setScheme("http");
|
||||
request.setServerName("www.example.com");
|
||||
request.setContextPath("/mycontext");
|
||||
request.setRequestURI("/mycontext/secure/page.html");
|
||||
|
||||
public void testRedirectedToLoginFormAndSessionShowsOriginalTargetWithExoticPortWhenAuthenticationException()
|
||||
throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure/page.html");
|
||||
request.setServerPort(8080);
|
||||
request.setScheme("http");
|
||||
request.setServerName("www.example.com");
|
||||
request.setContextPath("/mycontext");
|
||||
request.setRequestURI("/mycontext/secure/page.html");
|
||||
// Setup the FilterChain to thrown an authentication failure exception
|
||||
MockFilterChain chain = new MockFilterChain(false, true, false, false);
|
||||
|
||||
// Setup the FilterChain to thrown an authentication failure exception
|
||||
MockFilterChain chain = new MockFilterChain(false, true, false, false);
|
||||
// Test
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
filter.setPortResolver(new MockPortResolver(8080, 8443));
|
||||
/*
|
||||
* Disabled the call to afterPropertiesSet as it requires
|
||||
* applicationContext to be injected before it is invoked. We do not
|
||||
* have this filter configured in IOC for this test hence no
|
||||
* ApplicationContext
|
||||
*/
|
||||
// filter.afterPropertiesSet();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, chain);
|
||||
assertEquals("/mycontext/login.jsp", response.getRedirectedUrl());
|
||||
assertEquals("http://www.example.com:8080/mycontext/secure/page.html", AbstractProcessingFilter
|
||||
.obtainFullRequestUrl(request));
|
||||
}
|
||||
|
||||
// Test
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
filter.setPortResolver(new MockPortResolver(8080, 8443));
|
||||
filter.afterPropertiesSet();
|
||||
public void testStartupDetectsMissingAuthenticationEntryPoint() throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, chain);
|
||||
assertEquals("/mycontext/login.jsp", response.getRedirectedUrl());
|
||||
assertEquals("http://www.example.com:8080/mycontext/secure/page.html",
|
||||
AbstractProcessingFilter.obtainFullRequestUrl(request));
|
||||
}
|
||||
try {
|
||||
filter.afterPropertiesSet();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertEquals("authenticationEntryPoint must be specified", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testStartupDetectsMissingAuthenticationEntryPoint()
|
||||
throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
public void testStartupDetectsMissingPortResolver() throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
filter.setPortResolver(null);
|
||||
|
||||
try {
|
||||
filter.afterPropertiesSet();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("authenticationEntryPoint must be specified", expected.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
filter.afterPropertiesSet();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertEquals("portResolver must be specified", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testStartupDetectsMissingPortResolver()
|
||||
throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
filter.setPortResolver(null);
|
||||
public void testSuccessfulAccessGrant() throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure/page.html");
|
||||
|
||||
try {
|
||||
filter.afterPropertiesSet();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("portResolver must be specified", expected.getMessage());
|
||||
}
|
||||
}
|
||||
// Setup the FilterChain to thrown no exceptions
|
||||
MockFilterChain chain = new MockFilterChain(false, false, false, false);
|
||||
|
||||
public void testSuccessfulAccessGrant() throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure/page.html");
|
||||
// Test
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
|
||||
// Setup the FilterChain to thrown no exceptions
|
||||
MockFilterChain chain = new MockFilterChain(false, false, false, false);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, chain);
|
||||
}
|
||||
|
||||
// Test
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint("/login.jsp"));
|
||||
public void testSuccessfulStartupAndShutdownDown() throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, chain);
|
||||
}
|
||||
filter.init(null);
|
||||
filter.destroy();
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
public void testSuccessfulStartupAndShutdownDown()
|
||||
throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
public void testThrowIOException() throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
|
||||
filter.init(null);
|
||||
filter.destroy();
|
||||
assertTrue(true);
|
||||
}
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(""));
|
||||
/*
|
||||
* Disabled the call to afterPropertiesSet as it requires
|
||||
* applicationContext to be injected before it is invoked. We do not
|
||||
* have this filter configured in IOC for this test hence no
|
||||
* ApplicationContext
|
||||
*/
|
||||
// filter.afterPropertiesSet();
|
||||
try {
|
||||
filter.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(), new MockFilterChain(false,
|
||||
false, false, true));
|
||||
fail("Should have thrown IOException");
|
||||
}
|
||||
catch (IOException e) {
|
||||
assertNull("The IOException thrown should not have been wrapped", e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
public void testThrowIOException() throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
public void testThrowServletException() throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(""));
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(""));
|
||||
/*
|
||||
* Disabled the call to afterPropertiesSet as it requires
|
||||
* applicationContext to be injected before it is invoked. We do not
|
||||
* have this filter configured in IOC for this test hence no
|
||||
* ApplicationContext
|
||||
*/
|
||||
// filter.afterPropertiesSet();
|
||||
try {
|
||||
filter.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(), new MockFilterChain(false,
|
||||
false, true, false));
|
||||
fail("Should have thrown ServletException");
|
||||
}
|
||||
catch (ServletException e) {
|
||||
assertNull("The ServletException thrown should not have been wrapped", e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
filter.afterPropertiesSet();
|
||||
// ~ Inner Classes
|
||||
// ==================================================================================================
|
||||
|
||||
try {
|
||||
filter.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(),
|
||||
new MockFilterChain(false, false, false, true));
|
||||
fail("Should have thrown IOException");
|
||||
} catch (IOException e) {
|
||||
assertNull("The IOException thrown should not have been wrapped", e.getCause());
|
||||
}
|
||||
}
|
||||
private class MockFilterChain implements FilterChain {
|
||||
private boolean throwAccessDenied;
|
||||
|
||||
public void testThrowServletException() throws Exception {
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
|
||||
private boolean throwAuthenticationFailure;
|
||||
|
||||
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(""));
|
||||
private boolean throwIOException;
|
||||
|
||||
filter.afterPropertiesSet();
|
||||
private boolean throwServletException;
|
||||
|
||||
try {
|
||||
filter.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(),
|
||||
new MockFilterChain(false, false, true, false));
|
||||
fail("Should have thrown ServletException");
|
||||
} catch (ServletException e) {
|
||||
assertNull("The ServletException thrown should not have been wrapped", e.getCause());
|
||||
}
|
||||
}
|
||||
public MockFilterChain(boolean throwAccessDenied, boolean throwAuthenticationFailure,
|
||||
boolean throwServletException, boolean throwIOException) {
|
||||
this.throwAccessDenied = throwAccessDenied;
|
||||
this.throwAuthenticationFailure = throwAuthenticationFailure;
|
||||
this.throwServletException = throwServletException;
|
||||
this.throwIOException = throwIOException;
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
|
||||
if (throwAccessDenied) {
|
||||
throw new AccessDeniedException("As requested");
|
||||
}
|
||||
|
||||
private class MockFilterChain implements FilterChain {
|
||||
private boolean throwAccessDenied;
|
||||
private boolean throwAuthenticationFailure;
|
||||
private boolean throwIOException;
|
||||
private boolean throwServletException;
|
||||
if (throwAuthenticationFailure) {
|
||||
throw new BadCredentialsException("As requested");
|
||||
}
|
||||
|
||||
public MockFilterChain(boolean throwAccessDenied, boolean throwAuthenticationFailure,
|
||||
boolean throwServletException, boolean throwIOException) {
|
||||
this.throwAccessDenied = throwAccessDenied;
|
||||
this.throwAuthenticationFailure = throwAuthenticationFailure;
|
||||
this.throwServletException = throwServletException;
|
||||
this.throwIOException = throwIOException;
|
||||
}
|
||||
if (throwServletException) {
|
||||
throw new ServletException("As requested");
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
if (throwAccessDenied) {
|
||||
throw new AccessDeniedException("As requested");
|
||||
}
|
||||
|
||||
if (throwAuthenticationFailure) {
|
||||
throw new BadCredentialsException("As requested");
|
||||
}
|
||||
|
||||
if (throwServletException) {
|
||||
throw new ServletException("As requested");
|
||||
}
|
||||
|
||||
if (throwIOException) {
|
||||
throw new IOException("As requested");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (throwIOException) {
|
||||
throw new IOException("As requested");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
|||
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
|
||||
services.setKey("key");
|
||||
services.setUserDetailsService(new MockAuthenticationDao(null, true));
|
||||
services.afterPropertiesSet();
|
||||
//services.afterPropertiesSet();
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("dc");
|
||||
|
@ -114,7 +114,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
|||
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
|
||||
services.setKey("key");
|
||||
services.setUserDetailsService(new MockAuthenticationDao(null, true));
|
||||
services.afterPropertiesSet();
|
||||
//services.afterPropertiesSet();
|
||||
|
||||
Cookie cookie = new Cookie("unrelated_cookie", "foobar");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
@ -137,7 +137,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
|||
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
|
||||
services.setKey("key");
|
||||
services.setUserDetailsService(new MockAuthenticationDao(user, false));
|
||||
services.afterPropertiesSet();
|
||||
// services.afterPropertiesSet();
|
||||
|
||||
Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
|
||||
generateCorrectCookieContentForToken(System.currentTimeMillis() - 1000000, "someone", "password", "key"));
|
||||
|
@ -163,7 +163,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
|||
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
|
||||
services.setKey("key");
|
||||
services.setUserDetailsService(new MockAuthenticationDao(user, false));
|
||||
services.afterPropertiesSet();
|
||||
//services.afterPropertiesSet();
|
||||
|
||||
Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
|
||||
new String(Base64.encodeBase64("x".getBytes())));
|
||||
|
@ -188,7 +188,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
|||
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
|
||||
services.setKey("key");
|
||||
services.setUserDetailsService(new MockAuthenticationDao(user, false));
|
||||
services.afterPropertiesSet();
|
||||
//services.afterPropertiesSet();
|
||||
|
||||
Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
|
||||
"NOT_BASE_64_ENCODED");
|
||||
|
@ -214,7 +214,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
|||
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
|
||||
services.setKey("key");
|
||||
services.setUserDetailsService(new MockAuthenticationDao(user, false));
|
||||
services.afterPropertiesSet();
|
||||
//services.afterPropertiesSet();
|
||||
|
||||
Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
|
||||
generateCorrectCookieContentForToken(System.currentTimeMillis() + 1000000, "someone", "password",
|
||||
|
@ -241,7 +241,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
|||
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
|
||||
services.setKey("key");
|
||||
services.setUserDetailsService(new MockAuthenticationDao(user, false));
|
||||
services.afterPropertiesSet();
|
||||
//services.afterPropertiesSet();
|
||||
|
||||
Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
|
||||
new String(Base64.encodeBase64("username:NOT_A_NUMBER:signature".getBytes())));
|
||||
|
@ -263,7 +263,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
|||
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
|
||||
services.setKey("key");
|
||||
services.setUserDetailsService(new MockAuthenticationDao(null, true));
|
||||
services.afterPropertiesSet();
|
||||
//services.afterPropertiesSet();
|
||||
|
||||
Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
|
||||
generateCorrectCookieContentForToken(System.currentTimeMillis() + 1000000, "someone", "password", "key"));
|
||||
|
@ -288,7 +288,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
|||
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
|
||||
services.setKey("key");
|
||||
services.setUserDetailsService(new MockAuthenticationDao(user, false));
|
||||
services.afterPropertiesSet();
|
||||
// services.afterPropertiesSet();
|
||||
|
||||
Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
|
||||
generateCorrectCookieContentForToken(System.currentTimeMillis() + 1000000, "someone", "password", "key"));
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.acegisecurity</groupId>
|
||||
<artifactId>acegi-security-samples</artifactId>
|
||||
<version>1.0.4-SNAPSHOT</version>
|
||||
<version>1.0.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>acegi-security-sample-annotations</artifactId>
|
||||
<name>Acegi Security System for Spring - Annotations sample</name>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>org.acegisecurity</groupId>
|
||||
<artifactId>acegi-security-parent</artifactId>
|
||||
<version>1.0.4-SNAPSHOT</version>
|
||||
<version>1.0.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>acegi-security-sandbox</artifactId>
|
||||
<name>Acegi Security System for Spring - Sandbox</name>
|
||||
|
@ -27,7 +27,7 @@
|
|||
<dependency>
|
||||
<groupId>org.acegisecurity</groupId>
|
||||
<artifactId>acegi-security</artifactId>
|
||||
<version>1.1-SNAPSHOT</version>
|
||||
<version>1.0.5-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
@ -5,39 +5,40 @@
|
|||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**/*.java" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="var" path="M2_REPO/antlr/antlr/2.7.6/antlr-2.7.6.jar" sourcepath="M2_REPO/antlr/antlr/2.7.6/antlr-2.7.6-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.9/log4j-1.2.9.jar" sourcepath="M2_REPO/log4j/log4j/1.2.9/log4j-1.2.9-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/hsqldb/hsqldb/1.8.0.4/hsqldb-1.8.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/apache/directory/shared/shared-ldap/0.9.5.3/shared-ldap-0.9.5.3.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/acegisecurity/acegi-security/1.0.5-SNAPSHOT/acegi-security-1.0.5-SNAPSHOT.jar" sourcepath="M2_REPO/org/acegisecurity/acegi-security/1.0.5-SNAPSHOT/acegi-security-1.0.5-SNAPSHOT-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/apache/directory/shared/shared-asn1/0.9.5.3/shared-asn1-0.9.5.3.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/net/sf/ehcache/ehcache/1.2.4/ehcache-1.2.4.jar" sourcepath="M2_REPO/net/sf/ehcache/ehcache/1.2.4/ehcache-1.2.4-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/apache/directory/server/apacheds-core/1.0.0/apacheds-core-1.0.0.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/commons-collections/commons-collections/3.1/commons-collections-3.1.jar" sourcepath="M2_REPO/commons-collections/commons-collections/3.1/commons-collections-3.1-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/cas/casclient/2.0.11/casclient-2.0.11.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-beans/2.0.4/spring-beans-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/jdbm/jdbm/1.0/jdbm-1.0.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-mock/2.0.4/spring-mock-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-dao/2.0.4/spring-dao-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-remoting/2.0.4/spring-remoting-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-jdbc/2.0.4/spring-jdbc-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/aspectj/aspectjrt/1.2/aspectjrt-1.2.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/junit/junit/3.8.1/junit-3.8.1.jar" sourcepath="M2_REPO/junit/junit/3.8.1/junit-3.8.1-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/taglibs/standard/1.0.6/standard-1.0.6.jar" sourcepath="M2_REPO/taglibs/standard/1.0.6/standard-1.0.6-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/apache/directory/server/apacheds-core-shared/1.0.0/apacheds-core-shared-1.0.0.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-web/2.0.4/spring-web-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-context/2.0.4/spring-context-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-aop/2.0.4/spring-aop-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/javax/servlet/jsp-api/2.0/jsp-api-2.0.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar" sourcepath="M2_REPO/javax/servlet/servlet-api/2.4/servlet-api-2.4-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-log4j12/1.0.1/slf4j-log4j12-1.0.1.jar" sourcepath="M2_REPO/org/slf4j/slf4j-log4j12/1.0.1/slf4j-log4j12-1.0.1-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-core/2.0.4/spring-core-2.0.4.jar" sourcepath="/spring"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/apache/directory/shared/shared-asn1/0.9.5.3/shared-asn1-0.9.5.3.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-support/2.0.4/spring-support-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar" sourcepath="M2_REPO/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-beans/2.0.4/spring-beans-2.0.4.jar" sourcepath="/spring"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-mock/2.0.4/spring-mock-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-dao/2.0.4/spring-dao-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/apache/directory/shared/shared-ldap/0.9.5.3/shared-ldap-0.9.5.3.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/javax/servlet/jsp-api/2.0/jsp-api-2.0.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/commons-codec/commons-codec/1.3/commons-codec-1.3.jar" sourcepath="M2_REPO/commons-codec/commons-codec/1.3/commons-codec-1.3-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-jdbc/2.0.4/spring-jdbc-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-log4j12/1.0.1/slf4j-log4j12-1.0.1.jar" sourcepath="M2_REPO/org/slf4j/slf4j-log4j12/1.0.1/slf4j-log4j12-1.0.1-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/aspectj/aspectjrt/1.2/aspectjrt-1.2.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/antlr/antlr/2.7.6/antlr-2.7.6.jar" sourcepath="M2_REPO/antlr/antlr/2.7.6/antlr-2.7.6-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-aop/2.0.4/spring-aop-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/commons-lang/commons-lang/2.1/commons-lang-2.1.jar" sourcepath="M2_REPO/commons-lang/commons-lang/2.1/commons-lang-2.1-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar" sourcepath="M2_REPO/javax/servlet/servlet-api/2.4/servlet-api-2.4-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.9/log4j-1.2.9.jar" sourcepath="M2_REPO/log4j/log4j/1.2.9/log4j-1.2.9-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-web/2.0.4/spring-web-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/oro/oro/2.0.8/oro-2.0.8.jar" sourcepath="M2_REPO/oro/oro/2.0.8/oro-2.0.8-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/junit/junit/3.8.1/junit-3.8.1.jar" sourcepath="M2_REPO/junit/junit/3.8.1/junit-3.8.1-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/acegisecurity/acegi-security-tiger/1.0.5-SNAPSHOT/acegi-security-tiger-1.0.5-SNAPSHOT.jar" sourcepath="M2_REPO/org/acegisecurity/acegi-security-tiger/1.0.5-SNAPSHOT/acegi-security-tiger-1.0.5-SNAPSHOT-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/hsqldb/hsqldb/1.8.0.4/hsqldb-1.8.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-context/2.0.4/spring-context-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/taglibs/standard/1.0.6/standard-1.0.6.jar" sourcepath="M2_REPO/taglibs/standard/1.0.6/standard-1.0.6-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/jmock/jmock/1.0.1/jmock-1.0.1.jar" sourcepath="M2_REPO/jmock/jmock/1.0.1/jmock-1.0.1-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/aopalliance/aopalliance/1.0/aopalliance-1.0.jar" sourcepath="M2_REPO/aopalliance/aopalliance/1.0/aopalliance-1.0-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/commons-codec/commons-codec/1.3/commons-codec-1.3.jar" sourcepath="M2_REPO/commons-codec/commons-codec/1.3/commons-codec-1.3-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/cas/casclient/2.0.11/casclient-2.0.11.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/commons-lang/commons-lang/2.1/commons-lang-2.1.jar" sourcepath="M2_REPO/commons-lang/commons-lang/2.1/commons-lang-2.1-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/oro/oro/2.0.8/oro-2.0.8.jar" sourcepath="M2_REPO/oro/oro/2.0.8/oro-2.0.8-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/apache/directory/server/apacheds-core/1.0.0/apacheds-core-1.0.0.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-remoting/2.0.4/spring-remoting-2.0.4.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/acegisecurity/acegi-security/1.0.5-SNAPSHOT/acegi-security-1.0.5-SNAPSHOT.jar" sourcepath="M2_REPO/org/acegisecurity/acegi-security/1.0.5-SNAPSHOT/acegi-security-1.0.5-SNAPSHOT-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/apache/directory/server/apacheds-core-shared/1.0.0/apacheds-core-shared-1.0.0.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/net/sf/ehcache/ehcache/1.2.4/ehcache-1.2.4.jar" sourcepath="M2_REPO/net/sf/ehcache/ehcache/1.2.4/ehcache-1.2.4-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-core/2.0.4/spring-core-2.0.4.jar" sourcepath="/spring"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
|
|
@ -9,8 +9,12 @@
|
|||
<buildCommand>
|
||||
<name>org.eclipse.wst.validation.validationbuilder</name>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.springframework.ide.eclipse.core.springbuilder</name>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.springframework.ide.eclipse.core.springnature</nature>
|
||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#Wed Jun 06 14:00:16 EST 2007
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.3
|
||||
#Sun Jun 17 10:48:58 EST 2007
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.source=1.3
|
||||
org.eclipse.jdt.core.compiler.compliance=1.3
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
<version>2.0.0-M1</version>
|
||||
<url>http://maven.apache.org</url>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.acegisecurity</groupId>
|
||||
<artifactId>acegi-security-tiger</artifactId>
|
||||
<version>1.0.5-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-remoting</artifactId>
|
||||
|
|
|
@ -80,14 +80,15 @@ public class AuthenticationMechanismBeanDefinitionParser extends AbstractBeanDef
|
|||
* Creates a default bean definition.
|
||||
* @return
|
||||
*/
|
||||
protected static RootBeanDefinition createBeanDefinitionWithDefaults() {
|
||||
RootBeanDefinition authMechanismBeanDef = new RootBeanDefinition(ProviderManager.class);
|
||||
protected static RootBeanDefinition createAndRegisterBeanDefinitionWithDefaults(ParserContext parserContext) {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(ProviderManager.class);
|
||||
ManagedList providers = new ManagedList();
|
||||
// create authentication-repository (DaoAuthenticationProvider) and add that to list
|
||||
RootBeanDefinition authRepo = AuthenticationRepositoryBeanDefinitionParser.createBeanDefinitionWithDefaults();
|
||||
providers.add(authRepo);
|
||||
authMechanismBeanDef.getPropertyValues().addPropertyValue("providers", providers);
|
||||
return authMechanismBeanDef;
|
||||
beanDefinition.getPropertyValues().addPropertyValue("providers", providers);
|
||||
parserContext.getReaderContext().registerWithGeneratedName(beanDefinition);
|
||||
return beanDefinition;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ package org.acegisecurity.config;
|
|||
|
||||
import org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices;
|
||||
import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
|
@ -51,15 +52,19 @@ public class AuthenticationProcessingFilterBeanDefinitionParser extends Abstract
|
|||
}
|
||||
}
|
||||
|
||||
protected static RootBeanDefinition createBeandefinitionWithDefaults() {
|
||||
protected static RootBeanDefinition createBeandefinitionWithDefaults(ParserContext parserContext, RootBeanDefinition authenticationManager, RootBeanDefinition rememberMeServices) {
|
||||
RootBeanDefinition definition = new RootBeanDefinition(AuthenticationProcessingFilter.class);
|
||||
definition.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
AuthenticationMechanismBeanDefinitionParser.createBeanDefinitionWithDefaults());
|
||||
definition.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
RememberMeServicesBeanDefinitionParser.doCreateBeanDefintionWithDefaults());
|
||||
definition.getPropertyValues().addPropertyValue("authenticationManager",authenticationManager);
|
||||
definition.getPropertyValues().addPropertyValue("rememberMeServices",rememberMeServices);
|
||||
// RootBeanDefinition beanDefinition = AuthenticationMechanismBeanDefinitionParser.createAndRegisterBeanDefinitionWithDefaults(parserContext);
|
||||
// definition.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
// parserContext.getReaderContext().getRegistry().getBeanDefinition(beanDefinition.getBeanClassName()));
|
||||
// definition.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
// RememberMeServicesBeanDefinitionParser.createAndRegisterBeanDefintionWithDefaults(parserContext));
|
||||
/* TODO: There should not be any defaults for these urls ?!?! */
|
||||
definition.getPropertyValues().addPropertyValue("authenticationFailureUrl", "/acegilogin.jsp?login_error=1");
|
||||
definition.getPropertyValues().addPropertyValue("defaultTargetUrl", "/");
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,28 @@
|
|||
*/
|
||||
package org.acegisecurity.config;
|
||||
|
||||
import org.acegisecurity.context.HttpSessionContextIntegrationFilter;
|
||||
import org.acegisecurity.ui.logout.LogoutFilter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.acegisecurity.AuthenticationManager;
|
||||
import org.acegisecurity.annotation.SecurityAnnotationAttributes;
|
||||
import org.acegisecurity.intercept.method.MethodDefinitionAttributes;
|
||||
import org.acegisecurity.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
|
||||
import org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
import org.acegisecurity.intercept.web.FilterInvocationDefinitionDecorator;
|
||||
import org.acegisecurity.intercept.web.FilterInvocationDefinitionSourceMapping;
|
||||
import org.acegisecurity.intercept.web.FilterSecurityInterceptor;
|
||||
import org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
|
||||
import org.acegisecurity.runas.RunAsManagerImpl;
|
||||
import org.acegisecurity.vote.AffirmativeBased;
|
||||
import org.acegisecurity.vote.AuthenticatedVoter;
|
||||
import org.acegisecurity.vote.RoleVoter;
|
||||
import org.acegisecurity.vote.UnanimousBased;
|
||||
import org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Element;
|
||||
|
@ -21,28 +37,181 @@ import org.w3c.dom.Element;
|
|||
* @author Vishal Puri
|
||||
*
|
||||
*/
|
||||
public class AutoConfigBeanDefinitionParser implements BeanDefinitionParser {
|
||||
public class AutoConfigBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private RootBeanDefinition authenticationManager;
|
||||
|
||||
private RootBeanDefinition rememberMeServices;
|
||||
|
||||
private ManagedList decisionVoters = new ManagedList();
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
// authentication manager
|
||||
this.authenticationManager = AuthenticationMechanismBeanDefinitionParser
|
||||
.createAndRegisterBeanDefinitionWithDefaults(parserContext);
|
||||
// remembermeServices
|
||||
this.rememberMeServices = RememberMeServicesBeanDefinitionParser
|
||||
.createAndRegisterBeanDefintionWithDefaults(parserContext);
|
||||
// flters
|
||||
createAndRegisterBeanDefinitionForHttpSessionContextIntegrationFilter(parserContext);
|
||||
createAndRegisterBeanDefinitionForLogoutFilter(parserContext);
|
||||
createAndRegisterBeanDefinitionForAuthenticationProcessingFilter(parserContext);
|
||||
createAndRegisterBeanDefinitionForLogoutFilter(parserContext, rememberMeServices);
|
||||
createAndRegisterBeanDefinitionForAuthenticationProcessingFilter(parserContext, authenticationManager,
|
||||
rememberMeServices);
|
||||
createAndRegisterBeanDefinitionForRememberMeProcessingFilter(parserContext, authenticationManager);
|
||||
createAndRegisterBeanDefinitionForExceptionTranslationFilter(parserContext);
|
||||
createAndRegisterBeanDefintionForSecurityContextHolderAwareRequestFilter(parserContext);
|
||||
|
||||
// method interceptor
|
||||
createAndRegisterBeanDefinitinoForMethodDefinitionSourceAdvisor(parserContext, authenticationManager);
|
||||
createAndRegisterDefaultAdvisorAutoProxyCreator(parserContext);
|
||||
|
||||
// filter security interceptor
|
||||
createAndRegisterBeanDefinitionForFilterSecurityInterceptor(parserContext, authenticationManager);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void createAndRegisterBeanDefinitionForAuthenticationProcessingFilter(ParserContext parserContext) {
|
||||
RootBeanDefinition defintion = AuthenticationProcessingFilterBeanDefinitionParser.createBeandefinitionWithDefaults();
|
||||
private void createAndRegisterBeanDefintionForSecurityContextHolderAwareRequestFilter(ParserContext parserContext) {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class);
|
||||
registerBeanDefinition(parserContext, beanDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates <code>FilterSecurityInterceptor</code> bean definition and
|
||||
* register it with the <code>ParserContext</code>
|
||||
*
|
||||
* @param parserContext To register the bean definition with
|
||||
* @param authenticationManager The <code>AuthenticationManager</code> to
|
||||
* set as a property in the bean definition
|
||||
*/
|
||||
private void createAndRegisterBeanDefinitionForFilterSecurityInterceptor(ParserContext parserContext,
|
||||
RootBeanDefinition authenticationManager) {
|
||||
RootBeanDefinition filterInvocationInterceptor = new RootBeanDefinition(FilterSecurityInterceptor.class);
|
||||
filterInvocationInterceptor.getPropertyValues()
|
||||
.addPropertyValue("authenticationManager", authenticationManager);
|
||||
RootBeanDefinition accessDecisionManager = createAccessDecisionManagerAffirmativeBased();
|
||||
filterInvocationInterceptor.getPropertyValues()
|
||||
.addPropertyValue("accessDecisionManager", accessDecisionManager);
|
||||
|
||||
FilterInvocationDefinitionDecorator source = new FilterInvocationDefinitionDecorator();
|
||||
source.setDecorated(new PathBasedFilterInvocationDefinitionMap());
|
||||
|
||||
FilterInvocationDefinitionSourceMapping mapping = new FilterInvocationDefinitionSourceMapping();
|
||||
|
||||
String url1 = "/acegilogin.jsp";
|
||||
String value1 = "IS_AUTHENTICATED_ANONYMOUSLY";
|
||||
|
||||
String url2 = "/**";
|
||||
String value2 = "IS_AUTHENTICATED_REMEMBERED";
|
||||
|
||||
mapping.setUrl(url1);
|
||||
mapping.addConfigAttribute(value1);
|
||||
|
||||
mapping.setUrl(url2);
|
||||
mapping.addConfigAttribute(value2);
|
||||
|
||||
List mappings = new ArrayList();
|
||||
mappings.add(mapping);
|
||||
source.setMappings(mappings);
|
||||
filterInvocationInterceptor.getPropertyValues().addPropertyValue("objectDefinitionSource",
|
||||
source.getDecorated());
|
||||
registerBeanDefinition(parserContext, filterInvocationInterceptor);
|
||||
}
|
||||
|
||||
private RootBeanDefinition createAccessDecisionManagerAffirmativeBased() {
|
||||
RootBeanDefinition accessDecisionManager = new RootBeanDefinition(AffirmativeBased.class);
|
||||
accessDecisionManager.getPropertyValues().addPropertyValue("allowIfAllAbstainDecisions", Boolean.FALSE);
|
||||
RootBeanDefinition authenticatedVoter = new RootBeanDefinition(AuthenticatedVoter.class);
|
||||
this.decisionVoters.add(authenticatedVoter);
|
||||
accessDecisionManager.getPropertyValues().addPropertyValue("decisionVoters", decisionVoters);
|
||||
return accessDecisionManager;
|
||||
}
|
||||
|
||||
private void createAndRegisterDefaultAdvisorAutoProxyCreator(ParserContext parserContext) {
|
||||
registerBeanDefinition(parserContext, new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
|
||||
}
|
||||
|
||||
private void createAndRegisterBeanDefinitinoForMethodDefinitionSourceAdvisor(ParserContext parserContext,
|
||||
RootBeanDefinition authenticationManager) {
|
||||
RootBeanDefinition methodSecurityAdvisor = new RootBeanDefinition(MethodDefinitionSourceAdvisor.class);
|
||||
|
||||
RootBeanDefinition securityInterceptor = createMethodSecurityInterceptor(authenticationManager);
|
||||
methodSecurityAdvisor.getConstructorArgumentValues().addIndexedArgumentValue(0, securityInterceptor);
|
||||
registerBeanDefinition(parserContext, methodSecurityAdvisor);
|
||||
|
||||
}
|
||||
|
||||
private RootBeanDefinition createAccessDecisionManagerUnanimousBased() {
|
||||
RootBeanDefinition accessDecisionManager = new RootBeanDefinition(UnanimousBased.class);
|
||||
accessDecisionManager.getPropertyValues().addPropertyValue("allowIfAllAbstainDecisions", Boolean.FALSE);
|
||||
RootBeanDefinition roleVoter = createRoleVoter();
|
||||
decisionVoters.add(roleVoter);
|
||||
accessDecisionManager.getPropertyValues().addPropertyValue("decisionVoters", decisionVoters);
|
||||
return accessDecisionManager;
|
||||
}
|
||||
|
||||
private RootBeanDefinition createRoleVoter() {
|
||||
return new RootBeanDefinition(RoleVoter.class);
|
||||
}
|
||||
|
||||
private RootBeanDefinition createMethodSecurityInterceptor(RootBeanDefinition authenticationManager) {
|
||||
RootBeanDefinition securityInterceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
|
||||
securityInterceptor.getPropertyValues().addPropertyValue("authenticationManager", authenticationManager);
|
||||
RootBeanDefinition accessDecisionManager = createAccessDecisionManagerUnanimousBased();
|
||||
securityInterceptor.getPropertyValues().addPropertyValue("accessDecisionManager", accessDecisionManager);
|
||||
securityInterceptor.getPropertyValues().addPropertyValue("validateConfigAttributes", Boolean.FALSE);
|
||||
RootBeanDefinition runAsManager = createRunAsManager();
|
||||
securityInterceptor.getPropertyValues().addPropertyValue("runAsManager", runAsManager);
|
||||
RootBeanDefinition objectDefinitionSource = createMethodDefinitionAttributes();
|
||||
securityInterceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", objectDefinitionSource);
|
||||
return securityInterceptor;
|
||||
}
|
||||
|
||||
private RootBeanDefinition createMethodDefinitionAttributes() {
|
||||
RootBeanDefinition objectDefinitionSource = new RootBeanDefinition(MethodDefinitionAttributes.class);
|
||||
RootBeanDefinition attributes = createSecurityAnnotationAttributes();
|
||||
objectDefinitionSource.getPropertyValues().addPropertyValue("attributes", attributes);
|
||||
return objectDefinitionSource;
|
||||
}
|
||||
|
||||
private RootBeanDefinition createSecurityAnnotationAttributes() {
|
||||
return new RootBeanDefinition(SecurityAnnotationAttributes.class);
|
||||
}
|
||||
|
||||
private RootBeanDefinition createRunAsManager() {
|
||||
RootBeanDefinition runAsManager = new RootBeanDefinition(RunAsManagerImpl.class);
|
||||
runAsManager.getPropertyValues().addPropertyValue("key", "my_run_as_password");
|
||||
return runAsManager;
|
||||
}
|
||||
|
||||
private void createAndRegisterBeanDefinitionForExceptionTranslationFilter(ParserContext parserContext) {
|
||||
registerBeanDefinition(parserContext, ExceptionTranslationFilterBeanDefinitionParser
|
||||
.createBeanDefinitionWithDefaults());
|
||||
}
|
||||
|
||||
private void createAndRegisterBeanDefinitionForRememberMeProcessingFilter(ParserContext parserContext,
|
||||
RootBeanDefinition authenticationManager) {
|
||||
registerBeanDefinition(parserContext, RememberMeFilterBeanDefinitionParser.createBeanDefinitionWithDefaults(
|
||||
parserContext, authenticationManager));
|
||||
}
|
||||
|
||||
private void createAndRegisterBeanDefinitionForAuthenticationProcessingFilter(ParserContext parserContext,
|
||||
RootBeanDefinition authenticationManager, RootBeanDefinition rememberMeServices) {
|
||||
RootBeanDefinition defintion = AuthenticationProcessingFilterBeanDefinitionParser
|
||||
.createBeandefinitionWithDefaults(parserContext, authenticationManager, rememberMeServices);
|
||||
registerBeanDefinition(parserContext, defintion);
|
||||
}
|
||||
|
||||
private void createAndRegisterBeanDefinitionForLogoutFilter(ParserContext parserContext) {
|
||||
RootBeanDefinition defintion =LogoutFilterBeanDefinitionParser.doCreateBeanDefinitionWithDefaults();
|
||||
private void createAndRegisterBeanDefinitionForLogoutFilter(ParserContext parserContext,
|
||||
RootBeanDefinition rememberMeServices) {
|
||||
RootBeanDefinition defintion = LogoutFilterBeanDefinitionParser
|
||||
.createBeanDefinitionWithDefaults(rememberMeServices);
|
||||
registerBeanDefinition(parserContext, defintion);
|
||||
}
|
||||
|
||||
private void createAndRegisterBeanDefinitionForHttpSessionContextIntegrationFilter(ParserContext parserContext) {
|
||||
RootBeanDefinition defintion = ContextIntegrationBeanDefinitionParser.doCreateBeanDefinitionWithDefaults();
|
||||
RootBeanDefinition defintion = ContextIntegrationBeanDefinitionParser.createBeanDefinitionWithDefaults();
|
||||
registerBeanDefinition(parserContext, defintion);
|
||||
// retrieveBeanDefinition(parserContext, o)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,7 +219,29 @@ public class AutoConfigBeanDefinitionParser implements BeanDefinitionParser {
|
|||
* @param defintion
|
||||
*/
|
||||
private void registerBeanDefinition(ParserContext parserContext, RootBeanDefinition defintion) {
|
||||
parserContext.getRegistry().registerBeanDefinition(parserContext.getReaderContext().generateBeanName(defintion), defintion);
|
||||
parserContext.getRegistry().registerBeanDefinition(
|
||||
parserContext.getReaderContext().generateBeanName(defintion), defintion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>BeanDefinition</code> of the specified type.
|
||||
*
|
||||
* @param parserContext
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
private RootBeanDefinition retrieveBeanDefinition(ParserContext parserContext, Class type) {
|
||||
String[] names = parserContext.getRegistry().getBeanDefinitionNames();
|
||||
for (String name : names) {
|
||||
BeanDefinition beanDefinition = parserContext.getRegistry().getBeanDefinition(name);
|
||||
if (type.isInstance(beanDefinition)) {
|
||||
return (RootBeanDefinition) beanDefinition;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Class ss(Object o) {
|
||||
return o.getClass();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,11 +75,11 @@ public class ContextIntegrationBeanDefinitionParser extends AbstractSingleBeanDe
|
|||
builder.addPropertyValue(ALLOW_SESSION_CREATION, Boolean.FALSE);
|
||||
}
|
||||
else {
|
||||
doCreateBeanDefinitionWithDefaults();
|
||||
createBeanDefinitionWithDefaults();
|
||||
}
|
||||
}
|
||||
|
||||
protected static RootBeanDefinition doCreateBeanDefinitionWithDefaults() {
|
||||
protected static RootBeanDefinition createBeanDefinitionWithDefaults() {
|
||||
RootBeanDefinition definition = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
|
||||
definition.getPropertyValues().addPropertyValue(ALLOW_SESSION_CREATION, Boolean.TRUE);
|
||||
return definition;
|
||||
|
|
|
@ -5,6 +5,7 @@ package org.acegisecurity.config;
|
|||
|
||||
import org.acegisecurity.ui.AccessDeniedHandlerImpl;
|
||||
import org.acegisecurity.ui.ExceptionTranslationFilter;
|
||||
import org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
|
@ -46,7 +47,7 @@ import org.w3c.dom.Element;
|
|||
* </p>
|
||||
*
|
||||
* @author Vishal Puri
|
||||
* @version
|
||||
* @version
|
||||
* @see {@link org.acegisecurity.ui.ExceptionTranslationFilter}
|
||||
* @see {@link org.acegisecurity.ui.AccessDeniedHandler}
|
||||
*/
|
||||
|
@ -62,6 +63,10 @@ public class ExceptionTranslationFilterBeanDefinitionParser extends AbstractBean
|
|||
|
||||
private static final String ENTRY_POINT_REF = "entryPointBeanRef";
|
||||
|
||||
private static final String LOGIN_FORM_URL = "loginFormUrl";
|
||||
|
||||
private static final String LOGIN_FORM_URL_VALUE = "/acegilogin.jsp";
|
||||
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
|
||||
RootBeanDefinition exceptionFilterDef = new RootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
|
@ -144,4 +149,29 @@ public class ExceptionTranslationFilterBeanDefinitionParser extends AbstractBean
|
|||
definition.getPropertyValues().addPropertyValue(property, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates <code>BeanDefintion</code> for
|
||||
* <code>ExceptionTranslationFilter</code> with it's default properties.
|
||||
* @return beanDefinition The bean defintion configured with default
|
||||
* properties
|
||||
*/
|
||||
protected static RootBeanDefinition createBeanDefinitionWithDefaults() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
beanDefinition.getPropertyValues().addPropertyValue("authenticationEntryPoint",
|
||||
createBeanDefintionForAuthenticationProcessingFilterEntryPoint());
|
||||
return beanDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates <code>BeanDefintion</code> for
|
||||
* <code>AuthenticationProcessingFilterEntryPoint</code> with it's default
|
||||
* properties.
|
||||
* @return beanDefinition The bean defintion configured with default
|
||||
*/
|
||||
protected static RootBeanDefinition createBeanDefintionForAuthenticationProcessingFilterEntryPoint() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(AuthenticationProcessingFilterEntryPoint.class);
|
||||
beanDefinition.getPropertyValues().addPropertyValue(LOGIN_FORM_URL, LOGIN_FORM_URL_VALUE);
|
||||
return beanDefinition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,13 +92,13 @@ public class LogoutFilterBeanDefinitionParser extends AbstractBeanDefinitionPars
|
|||
* @param isAutoconfig
|
||||
* @return definition
|
||||
*/
|
||||
protected static RootBeanDefinition doCreateBeanDefinitionWithDefaults() {
|
||||
protected static RootBeanDefinition createBeanDefinitionWithDefaults(RootBeanDefinition rememberMeServices) {
|
||||
RootBeanDefinition definition = new RootBeanDefinition(LogoutFilter.class);
|
||||
definition.getConstructorArgumentValues().addIndexedArgumentValue(0, REDIRECT_AFTER_LOGOUT_URL_VALUE);
|
||||
// create BeanDefinitions for LogoutHandlers
|
||||
// (TokenBasedRememberMeServices) and (SecuritycontextLogoutHandler)
|
||||
ManagedList handlers = new ManagedList();
|
||||
RootBeanDefinition rememberMeServices = RememberMeServicesBeanDefinitionParser.doCreateBeanDefintionWithDefaults();
|
||||
//RootBeanDefinition rememberMeServices = RememberMeServicesBeanDefinitionParser.doCreateBeanDefintionWithDefaults();
|
||||
handlers.add(rememberMeServices);
|
||||
handlers.add(new RootBeanDefinition(SecurityContextLogoutHandler.class));
|
||||
definition.getConstructorArgumentValues().addIndexedArgumentValue(1, handlers);
|
||||
|
|
|
@ -29,10 +29,6 @@ public class RememberMeFilterBeanDefinitionParser extends AbstractBeanDefinition
|
|||
Assert.notNull(parserContext, "ParserContext must not be null");
|
||||
|
||||
RootBeanDefinition rememberMeFilterBeanDef = new RootBeanDefinition(RememberMeProcessingFilter.class);
|
||||
|
||||
// detect all the required dependencies and autowire them by type
|
||||
rememberMeFilterBeanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_AUTODETECT);
|
||||
|
||||
// check if rememberMeServicesBeanRef is defined and if it's specified use its referred bean
|
||||
String rememberMeServicesRef = element.getAttribute(REMEMBER_ME_SERVICES_REF);
|
||||
if (StringUtils.hasLength(rememberMeServicesRef)) {
|
||||
|
@ -41,4 +37,10 @@ public class RememberMeFilterBeanDefinitionParser extends AbstractBeanDefinition
|
|||
}
|
||||
return rememberMeFilterBeanDef;
|
||||
}
|
||||
|
||||
protected static RootBeanDefinition createBeanDefinitionWithDefaults(ParserContext parserContext, RootBeanDefinition authenticationManager) {
|
||||
RootBeanDefinition definition= new RootBeanDefinition(RememberMeProcessingFilter.class);
|
||||
definition.getPropertyValues().addPropertyValue("authenticationManager",authenticationManager);
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,10 +72,11 @@ public class RememberMeServicesBeanDefinitionParser extends AbstractBeanDefiniti
|
|||
return rememberMeServicesBeanDef;
|
||||
}
|
||||
|
||||
protected static RootBeanDefinition doCreateBeanDefintionWithDefaults(){
|
||||
RootBeanDefinition definition = new RootBeanDefinition(TokenBasedRememberMeServices.class);
|
||||
definition.getPropertyValues().addPropertyValue(KEY, "key");
|
||||
return definition;
|
||||
protected static RootBeanDefinition createAndRegisterBeanDefintionWithDefaults(ParserContext parserContext){
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(TokenBasedRememberMeServices.class);
|
||||
beanDefinition.getPropertyValues().addPropertyValue(KEY, "key");
|
||||
parserContext.getReaderContext().registerWithGeneratedName(beanDefinition);
|
||||
return beanDefinition;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,8 +10,11 @@ import junit.framework.TestCase;
|
|||
|
||||
import org.acegisecurity.AuthenticationManager;
|
||||
import org.acegisecurity.context.HttpSessionContextIntegrationFilter;
|
||||
import org.acegisecurity.intercept.method.MethodDefinitionSource;
|
||||
import org.acegisecurity.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
|
||||
import org.acegisecurity.ui.logout.LogoutFilter;
|
||||
import org.acegisecurity.ui.logout.LogoutHandler;
|
||||
import org.acegisecurity.ui.rememberme.RememberMeProcessingFilter;
|
||||
import org.acegisecurity.ui.rememberme.RememberMeServices;
|
||||
import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
|
@ -47,7 +50,6 @@ public class AutoConfigBeanDefinitionParserTests extends TestCase {
|
|||
assertFalse(filter.isForceEagerSessionCreation());
|
||||
assertFalse(filter.isCloneFromHttpSession());
|
||||
}
|
||||
|
||||
|
||||
public void testLogoutFilterDefinitionCreatedWithDefaults() throws Exception {
|
||||
String[] names = bf.getBeanNamesForType(LogoutFilter.class);
|
||||
|
@ -71,8 +73,23 @@ public class AutoConfigBeanDefinitionParserTests extends TestCase {
|
|||
assertNotNull(authMgr);
|
||||
RememberMeServices remMeServices = filter.getRememberMeServices();
|
||||
assertNotNull(remMeServices);
|
||||
assertEquals("/acegilogin.jsp?login_error=1",filter.getAuthenticationFailureUrl());
|
||||
assertEquals( "/",filter.getDefaultTargetUrl());
|
||||
assertEquals("/acegilogin.jsp?login_error=1", filter.getAuthenticationFailureUrl());
|
||||
assertEquals("/", filter.getDefaultTargetUrl());
|
||||
}
|
||||
|
||||
public void testRememberMePRocessingFilterCreatedWithDefaults() {
|
||||
Map map = bf.getBeansOfType(RememberMeProcessingFilter.class);
|
||||
RememberMeProcessingFilter filter = (RememberMeProcessingFilter) map.values().iterator().next();
|
||||
}
|
||||
|
||||
public void testMethodDefinitionSourceAdvisorCreatedWithDefaults() throws Exception {
|
||||
Map map = bf.getBeansOfType(MethodDefinitionSourceAdvisor.class);
|
||||
assertEquals(1, map.size());
|
||||
MethodDefinitionSourceAdvisor advisor = (MethodDefinitionSourceAdvisor) map.values().iterator().next();
|
||||
Field transactionAttributeSource = makeAccessibleAndGetFieldByName(advisor.getClass().getDeclaredFields(), "transactionAttributeSource");
|
||||
assertNotNull(transactionAttributeSource);
|
||||
assertTrue(transactionAttributeSource.get(advisor) instanceof MethodDefinitionSource);
|
||||
|
||||
}
|
||||
|
||||
private Field makeAccessibleAndGetFieldByName(Field[] declaredFields, String name) {
|
||||
|
@ -85,4 +102,5 @@ public class AutoConfigBeanDefinitionParserTests extends TestCase {
|
|||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,5 +16,4 @@ public class RememberMeBeanDefinitionParserTest extends TestCase {
|
|||
assertEquals(1, mgr.getProviders().size());
|
||||
assertTrue(mgr.getProviders().get(0) instanceof DaoAuthenticationProvider);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -128,9 +128,9 @@
|
|||
<value>
|
||||
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
||||
PATTERN_TYPE_APACHE_ANT
|
||||
/secure/extreme/**=ROLE_SUPERVISOR
|
||||
/secure/**=IS_AUTHENTICATED_REMEMBERED
|
||||
/**=IS_AUTHENTICATED_ANONYMOUSLY
|
||||
/acegilogin.jsp=IS_AUTHENTICATED_ANONYMOUSLY
|
||||
/**=IS_AUTHENTICATED_REMEMBERED
|
||||
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
|
|
@ -25,26 +25,8 @@ http://www.springframework.org/schema/security http://www.springframework.org/sc
|
|||
<security:properties
|
||||
resource="classpath:org/acegisecurity/config/user.properties" />
|
||||
</security:principal-repository>
|
||||
|
||||
<!--<bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
|
||||
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
|
||||
<property name="accessDecisionManager">
|
||||
<bean class="org.acegisecurity.vote.AffirmativeBased">
|
||||
<property name="allowIfAllAbstainDecisions" value="false"/>
|
||||
<property name="decisionVoters">
|
||||
<list>
|
||||
<bean class="org.acegisecurity.vote.RoleVoter"/>
|
||||
<bean class="org.acegisecurity.vote.AuthenticatedVoter"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="objectDefinitionSource">
|
||||
<value>
|
||||
org.springframework.samples.petclinic.Clinic.*=IS_AUTHENTICATED_REMEMBERED
|
||||
org.springframework.samples.petclinic.Clinic.storeVisit=ROLE_SUPERVISOR
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
-->
|
||||
|
||||
<bean id="bankService" class="org.acegisecurity.BankServiceImpl"/>
|
||||
|
||||
|
||||
</beans>
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
vishal=ity,ROLE_ADMIN
|
||||
ity=vishal,ROLE_TELLER
|
||||
ity=vishal,ROLE_TELLER,ROLE_PERMISSION_LIST
|
||||
|
|
Loading…
Reference in New Issue