SEC-271: work on security:autoconfig

This commit is contained in:
Vishal Puri 2007-06-19 04:08:19 +00:00
parent 6e82a9bdfc
commit b2c30277f4
29 changed files with 2232 additions and 1499 deletions

View File

@ -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;
}
}

View File

@ -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>
* &lt;property name="exceptionMappings"&gt;
* &lt;property name=&quot;exceptionMappings&quot;&gt;
* &lt;props&gt;
* &lt;prop&gt; key="org.acegisecurity.BadCredentialsException"&gt;/bad_credentials.jsp&lt;/prop&gt;
* &lt;prop&gt; key=&quot;org.acegisecurity.BadCredentialsException&quot;&gt;/bad_credentials.jsp&lt;/prop&gt;
* &lt;/props&gt;
* &lt;/property&gt;
* </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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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 + &quot;:&quot; + expiryTime + &quot;:&quot; + Md5Hex(username + &quot;:&quot; + expiryTime + &quot;:&quot; + password + &quot;:&quot; + 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;
}
}

View File

@ -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;
}

View File

@ -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");
}
}
}
}

View File

@ -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"));

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -16,5 +16,4 @@ public class RememberMeBeanDefinitionParserTest extends TestCase {
assertEquals(1, mgr.getProviders().size());
assertTrue(mgr.getProviders().get(0) instanceof DaoAuthenticationProvider);
}
}

View File

@ -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>

View File

@ -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>

View File

@ -1,2 +1,2 @@
vishal=ity,ROLE_ADMIN
ity=vishal,ROLE_TELLER
ity=vishal,ROLE_TELLER,ROLE_PERMISSION_LIST