SEC-234: Allow pluggable AuthenticationDetailsSource strategy interface.

This commit is contained in:
Ben Alex 2006-04-26 05:24:49 +00:00
parent b1becf9277
commit a47a342ce6
13 changed files with 683 additions and 521 deletions

View File

@ -19,7 +19,8 @@ import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.acegisecurity.ui.AuthenticationDetailsSource;
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
import org.acegisecurity.userdetails.memory.UserAttribute;
@ -61,6 +62,7 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean {
//~ Instance fields ========================================================
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
private String key;
private UserAttribute userAttribute;
private boolean removeAfterRequest = true;
@ -96,8 +98,8 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean {
AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(key,
userAttribute.getPassword(), userAttribute.getAuthorities());
auth.setDetails(new WebAuthenticationDetails(
(HttpServletRequest) request, false));
auth.setDetails(authenticationDetailsSource.buildDetails(
(HttpServletRequest) request));
return auth;
}
@ -167,6 +169,13 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean {
return removeAfterRequest;
}
public void setAuthenticationDetailsSource(
AuthenticationDetailsSource authenticationDetailsSource) {
Assert.notNull(authenticationDetailsSource,
"AuthenticationDetailsSource required");
this.authenticationDetailsSource = authenticationDetailsSource;
}
public void setKey(String key) {
this.key = key;
}

View File

@ -143,6 +143,7 @@ public abstract class AbstractProcessingFilter implements Filter,
//~ 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();
@ -371,6 +372,13 @@ public abstract class AbstractProcessingFilter implements Filter,
this.eventPublisher = eventPublisher;
}
public void setAuthenticationDetailsSource(
AuthenticationDetailsSource authenticationDetailsSource) {
Assert.notNull(authenticationDetailsSource,
"AuthenticationDetailsSource required");
this.authenticationDetailsSource = authenticationDetailsSource;
}
public void setAuthenticationFailureUrl(String authenticationFailureUrl) {
this.authenticationFailureUrl = authenticationFailureUrl;
}

View File

@ -0,0 +1,41 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.ui;
import javax.servlet.http.HttpServletRequest;
/**
* Provides a {@link org.acegisecurity.Authentication#getDetails()} object for
* a given web request.
*
* @author Ben Alex
* @version $Id$
*/
public interface AuthenticationDetailsSource {
//~ Methods ================================================================
/**
* Called by a class when it wishes a new authentication details instance
* to be created.
*
* @param request the request object, which may be used by the
* authentication details object
*
* @return a fully-configured authentication details instance
*/
public Object buildDetails(HttpServletRequest request);
}

View File

@ -0,0 +1,69 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.ui;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import javax.servlet.http.HttpServletRequest;
/**
* Base implementation of {@link AuthenticationDetailsSource}.
*
* <P>
* By default will create an instance of <code>WebAuthenticationDetails</code>.
* Any object that accepts a <code>HttpServletRequest</code> as its sole
* constructor can be used instead of this default.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class AuthenticationDetailsSourceImpl
implements AuthenticationDetailsSource {
//~ Instance fields ========================================================
private Class clazz = WebAuthenticationDetails.class;
//~ Methods ================================================================
public Object buildDetails(HttpServletRequest request) {
try {
Constructor constructor = clazz.getConstructor(new Class[] {HttpServletRequest.class});
return constructor.newInstance(new Object[] {request});
} catch (NoSuchMethodException ex) {
ReflectionUtils.handleReflectionException(ex);
} catch (InvocationTargetException ex) {
ReflectionUtils.handleReflectionException(ex);
} catch (InstantiationException ex) {
ReflectionUtils.handleReflectionException(ex);
} catch (IllegalAccessException ex) {
ReflectionUtils.handleReflectionException(ex);
}
return null;
}
public void setClazz(Class clazz) {
Assert.notNull(clazz, "Class required");
this.clazz = clazz;
}
}

View File

@ -52,15 +52,8 @@ public class WebAuthenticationDetails implements SessionIdentifierAware,
*/
public WebAuthenticationDetails(HttpServletRequest request) {
this.remoteAddress = request.getRemoteAddr();
this.sessionId = request.getSession(true).getId();
doPopulateAdditionalInformation(request);
}
public WebAuthenticationDetails(HttpServletRequest request,
boolean forceSessionCreation) {
this.remoteAddress = request.getRemoteAddr();
HttpSession session = request.getSession(forceSessionCreation);
HttpSession session = request.getSession(false);
this.sessionId = (session != null) ? session.getId() : null;
doPopulateAdditionalInformation(request);

View File

@ -23,8 +23,9 @@ import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.AuthenticationDetailsSource;
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
import org.acegisecurity.ui.AuthenticationEntryPoint;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
@ -115,9 +116,15 @@ public class BasicProcessingFilter implements Filter, InitializingBean {
private AuthenticationEntryPoint authenticationEntryPoint;
private AuthenticationManager authenticationManager;
private boolean ignoreFailure = false;
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
//~ Methods ================================================================
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required");
this.authenticationDetailsSource = authenticationDetailsSource;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.authenticationManager,
"An AuthenticationManager is required");
@ -168,8 +175,7 @@ public class BasicProcessingFilter implements Filter, InitializingBean {
|| !existingAuth.isAuthenticated()) {
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,
password);
authRequest.setDetails(new WebAuthenticationDetails(
httpRequest, false));
authRequest.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
Authentication authResult;

View File

@ -19,7 +19,6 @@ import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.AbstractProcessingFilter;
import org.acegisecurity.ui.WebAuthenticationDetails;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
@ -105,7 +104,7 @@ public class CasProcessingFilter extends AbstractProcessingFilter {
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(username, password);
authRequest.setDetails(new WebAuthenticationDetails(request, false));
authRequest.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
return this.getAuthenticationManager().authenticate(authRequest);
}

View File

@ -1,4 +1,4 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,7 +15,42 @@
package org.acegisecurity.ui.digestauth;
import org.acegisecurity.AcegiMessageSource;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationServiceException;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.UserCache;
import org.acegisecurity.providers.dao.cache.NullUserCache;
import org.acegisecurity.ui.AuthenticationDetailsSource;
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.acegisecurity.util.StringSplitUtils;
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.factory.InitializingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.Map;
import javax.servlet.Filter;
@ -27,30 +62,6 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.acegisecurity.AcegiMessageSource;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationServiceException;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.UserCache;
import org.acegisecurity.providers.dao.cache.NullUserCache;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.acegisecurity.util.StringSplitUtils;
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.factory.InitializingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Processes a HTTP request's Digest authorization headers, putting the result
@ -84,9 +95,9 @@ import org.springframework.util.StringUtils;
*
* <p>
* If authentication fails, an {@link
* org.acegisecurity.ui.AuthenticationEntryPoint
* AuthenticationEntryPoint} implementation is called. This must always be
* {@link DigestProcessingFilterEntryPoint}, which will prompt the user to
* org.acegisecurity.ui.AuthenticationEntryPoint AuthenticationEntryPoint}
* implementation is called. This must always be {@link
* DigestProcessingFilterEntryPoint}, which will prompt the user to
* authenticate again via Digest authentication.
* </p>
*
@ -112,10 +123,11 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
//~ Instance fields ========================================================
private UserDetailsService userDetailsService;
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
private DigestProcessingFilterEntryPoint authenticationEntryPoint;
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
private UserCache userCache = new NullUserCache();
private UserDetailsService userDetailsService;
private boolean passwordAlreadyEncoded = false;
//~ Methods ================================================================
@ -369,10 +381,11 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
+ "' with response: '" + responseDigest + "'");
}
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(user, user.getPassword());
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(user,
user.getPassword());
authRequest.setDetails(new WebAuthenticationDetails(httpRequest, false));
authRequest.setDetails(authenticationDetailsSource.buildDetails(
(HttpServletRequest) request));
SecurityContextHolder.getContext().setAuthentication(authRequest);
}
@ -405,8 +418,8 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
* <code>response</code> independently. Provided as a static method to
* simplify the coding of user agents.
*
* @param passwordAlreadyEncoded true if the password argument is already encoded in
* the correct format. False if it is plain text.
* @param passwordAlreadyEncoded true if the password argument is already
* encoded in the correct format. False if it is plain text.
* @param username the user's login name.
* @param realm the name of the realm.
* @param password the user's password in plaintext or ready-encoded.
@ -419,7 +432,8 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
*
* @return the MD5 of the digest authentication response, encoded in hex
*
* @throws IllegalArgumentException if the supplied qop value is unsupported.
* @throws IllegalArgumentException if the supplied qop value is
* unsupported.
*/
public static String generateDigest(boolean passwordAlreadyEncoded,
String username, String realm, String password, String httpMethod,
@ -454,10 +468,6 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
return digestMd5;
}
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
public DigestProcessingFilterEntryPoint getAuthenticationEntryPoint() {
return authenticationEntryPoint;
}
@ -466,10 +476,17 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
return userCache;
}
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
public void init(FilterConfig ignored) throws ServletException {}
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
public void setAuthenticationDetailsSource(
AuthenticationDetailsSource authenticationDetailsSource) {
Assert.notNull(authenticationDetailsSource,
"AuthenticationDetailsSource required");
this.authenticationDetailsSource = authenticationDetailsSource;
}
public void setAuthenticationEntryPoint(
@ -488,4 +505,8 @@ public class DigestProcessingFilter implements Filter, InitializingBean,
public void setUserCache(UserCache userCache) {
this.userCache = userCache;
}
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
}
}

View File

@ -19,7 +19,8 @@ import org.acegisecurity.Authentication;
import org.acegisecurity.providers.rememberme.RememberMeAuthenticationToken;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.acegisecurity.ui.AuthenticationDetailsSource;
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
@ -116,6 +117,7 @@ public class TokenBasedRememberMeServices implements RememberMeServices,
//~ Instance fields ========================================================
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
private String key;
private String parameter = DEFAULT_PARAMETER;
private UserDetailsService userDetailsService;
@ -232,8 +234,8 @@ public class TokenBasedRememberMeServices implements RememberMeServices,
RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken(this.key,
userDetails, userDetails.getAuthorities());
auth.setDetails(new WebAuthenticationDetails(request,
false));
auth.setDetails(authenticationDetailsSource.buildDetails(
(HttpServletRequest) request));
return auth;
} else {
@ -347,7 +349,8 @@ public class TokenBasedRememberMeServices implements RememberMeServices,
return cookie;
}
protected Cookie makeValidCookie(long expiryTime, String tokenValueBase64, HttpServletRequest request) {
protected Cookie makeValidCookie(long expiryTime, String tokenValueBase64,
HttpServletRequest request) {
Cookie cookie = new Cookie(ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
tokenValueBase64);
cookie.setMaxAge(60 * 60 * 24 * 365 * 5); // 5 years
@ -356,6 +359,13 @@ public class TokenBasedRememberMeServices implements RememberMeServices,
return cookie;
}
public void setAuthenticationDetailsSource(
AuthenticationDetailsSource authenticationDetailsSource) {
Assert.notNull(authenticationDetailsSource,
"AuthenticationDetailsSource required");
this.authenticationDetailsSource = authenticationDetailsSource;
}
public void setKey(String key) {
this.key = key;
}

View File

@ -1,4 +1,4 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,7 +15,45 @@
package org.acegisecurity.ui.switchuser;
import org.acegisecurity.AccountExpiredException;
import org.acegisecurity.AcegiMessageSource;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationCredentialsNotFoundException;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.CredentialsExpiredException;
import org.acegisecurity.DisabledException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.LockedException;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.event.authentication.AuthenticationSwitchUserEvent;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.AuthenticationDetailsSource;
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
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.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.util.Assert;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -29,33 +67,6 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.acegisecurity.AccountExpiredException;
import org.acegisecurity.AcegiMessageSource;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationCredentialsNotFoundException;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.CredentialsExpiredException;
import org.acegisecurity.DisabledException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.LockedException;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.event.authentication.AuthenticationSwitchUserEvent;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
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.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.util.Assert;
/**
* Switch User processing filter responsible for user context switching.
@ -104,7 +115,6 @@ import org.springframework.util.Assert;
* </pre>
* </p>
*
*
* @author Mark St.Godard
* @version $Id$
*
@ -124,15 +134,16 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
//~ Instance fields ========================================================
private ApplicationEventPublisher eventPublisher;
// ~ Instance fields
// ========================================================
private UserDetailsService userDetailsService;
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
private String exitUserUrl = "/j_acegi_exit_user";
private String switchUserUrl = "/j_acegi_switch_user";
private String targetUrl;
// ~ Instance fields
// ========================================================
private UserDetailsService userDetailsService;
//~ Methods ================================================================
public void afterPropertiesSet() throws Exception {
@ -171,11 +182,9 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
Authentication original = getSourceAuthentication(current);
if (original == null) {
logger.error(
"Could not find original user Authentication object!");
logger.error("Could not find original user Authentication object!");
throw new AuthenticationCredentialsNotFoundException(messages
.getMessage(
"SwitchUserProcessingFilter.noOriginalAuthentication",
.getMessage("SwitchUserProcessingFilter.noOriginalAuthentication",
"Could not find original Authentication object"));
}
@ -197,27 +206,24 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
}
/**
* Attempt to switch to another user. If the user does not exist or
* is not active, return null.
* Attempt to switch to another user. If the user does not exist or is not
* active, return null.
*
* @param request The http request
*
* @return The new <code>Authentication</code> request if
* successfully switched to another user,
* <code>null</code> otherwise.
* @return The new <code>Authentication</code> request if successfully
* switched to another user, <code>null</code> otherwise.
*
* @throws AuthenticationException
* @throws UsernameNotFoundException If the target user is not
* found.
* @throws UsernameNotFoundException If the target user is not found.
* @throws LockedException DOCUMENT ME!
* @throws DisabledException If the target user is disabled.
* @throws AccountExpiredException If the target user account is
* @throws AccountExpiredException If the target user account is expired.
* @throws CredentialsExpiredException If the target user credentials are
* expired.
* @throws CredentialsExpiredException If the target user
* credentials are expired.
*/
protected Authentication attemptSwitchUser(
HttpServletRequest request) throws AuthenticationException {
protected Authentication attemptSwitchUser(HttpServletRequest request)
throws AuthenticationException {
UsernamePasswordAuthenticationToken targetUserRequest = null;
String username = request.getParameter(ACEGI_SECURITY_SWITCH_USERNAME_KEY);
@ -231,15 +237,13 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
}
// load the user by name
UserDetails targetUser = this.userDetailsService
.loadUserByUsername(username);
UserDetails targetUser = this.userDetailsService.loadUserByUsername(username);
// user not found
if (targetUser == null) {
throw new UsernameNotFoundException(messages.getMessage(
"SwitchUserProcessingFilter.usernameNotFound",
new Object[] {username},
"Username {0} not found"));
new Object[] {username}, "Username {0} not found"));
}
// account is expired
@ -252,8 +256,7 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
// user is disabled
if (!targetUser.isEnabled()) {
throw new DisabledException(messages.getMessage(
"SwitchUserProcessingFilter.disabled",
"User is disabled"));
"SwitchUserProcessingFilter.disabled", "User is disabled"));
}
// account is expired
@ -265,15 +268,13 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
// credentials expired
if (!targetUser.isCredentialsNonExpired()) {
throw new CredentialsExpiredException(messages
.getMessage(
throw new CredentialsExpiredException(messages.getMessage(
"SwitchUserProcessingFilter.credentialsExpired",
"User credentials have expired"));
}
// ok, create the switch user token
targetUserRequest = createSwitchUserToken(request,
username, targetUser);
targetUserRequest = createSwitchUserToken(request, username, targetUser);
if (logger.isDebugEnabled()) {
logger.debug("Switch User Token [" + targetUserRequest + "]");
@ -303,8 +304,7 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
* @see SwitchUserGrantedAuthority
*/
private UsernamePasswordAuthenticationToken createSwitchUserToken(
HttpServletRequest request, String username,
UserDetails targetUser) {
HttpServletRequest request, String username, UserDetails targetUser) {
UsernamePasswordAuthenticationToken targetUserRequest;
// grant an additional authority that contains the original Authentication object
@ -329,8 +329,8 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
targetUser.getPassword(), authorities);
// set details
targetUserRequest.setDetails(new WebAuthenticationDetails(
request, false));
targetUserRequest.setDetails(authenticationDetailsSource.buildDetails(
(HttpServletRequest) request));
return targetUserRequest;
}
@ -340,9 +340,8 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
/**
* @see javax.servlet.Filter#doFilter
*/
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
Assert.isInstanceOf(HttpServletRequest.class, request);
Assert.isInstanceOf(HttpServletResponse.class, response);
@ -355,12 +354,10 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
Authentication targetUser = attemptSwitchUser(httpRequest);
// update the current context to the new target user
SecurityContextHolder.getContext()
.setAuthentication(targetUser);
SecurityContextHolder.getContext().setAuthentication(targetUser);
// redirect to target url
httpResponse.sendRedirect(httpResponse
.encodeRedirectURL(httpRequest
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(httpRequest
.getContextPath() + targetUrl));
return;
@ -369,12 +366,11 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
Authentication originalUser = attemptExitUser(httpRequest);
// update the current context back to the original user
SecurityContextHolder.getContext()
.setAuthentication(originalUser);
SecurityContextHolder.getContext().setAuthentication(originalUser);
// redirect to target url
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(
httpRequest.getContextPath() + targetUrl));
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(httpRequest
.getContextPath() + targetUrl));
return;
}
@ -383,33 +379,28 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
}
/**
* Find the original <code>Authentication</code> object from
* the current user's granted authorities. A successfully switched
* user should have a <code>SwitchUserGrantedAuthority</code>
* that contains the original source user <code>Authentication</code>
* object.
* Find the original <code>Authentication</code> object from the current
* user's granted authorities. A successfully switched user should have a
* <code>SwitchUserGrantedAuthority</code> that contains the original
* source user <code>Authentication</code> object.
*
* @param current The current <code>Authentication</code>
* object
* @param current The current <code>Authentication</code> object
*
* @return The source user <code>Authentication</code>
* object or <code>null</code> otherwise.
* @return The source user <code>Authentication</code> object or
* <code>null</code> otherwise.
*/
private Authentication getSourceAuthentication(
Authentication current) {
private Authentication getSourceAuthentication(Authentication current) {
Authentication original = null;
// iterate over granted authorities and find the 'switch user' authority
GrantedAuthority[] authorities = current
.getAuthorities();
GrantedAuthority[] authorities = current.getAuthorities();
for (int i = 0; i < authorities.length; i++) {
// check for switch user type of authority
if (authorities[i] instanceof SwitchUserGrantedAuthority) {
original = ((SwitchUserGrantedAuthority) authorities[i])
.getSource();
logger.debug(
"Found original switch user granted authority ["
logger.debug("Found original switch user granted authority ["
+ original + "]");
}
}
@ -417,12 +408,10 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
return original;
}
public void init(FilterConfig ignored)
throws ServletException {}
public void init(FilterConfig ignored) throws ServletException {}
/**
* Checks the request URI for the presence
* of <tt>exitUserUrl</tt>.
* Checks the request URI for the presence of <tt>exitUserUrl</tt>.
*
* @param request The http servlet request
*
@ -431,12 +420,10 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
*
* @see SwitchUserProcessingFilter#exitUserUrl
*/
protected boolean requiresExitUser(
HttpServletRequest request) {
protected boolean requiresExitUser(HttpServletRequest request) {
String uri = stripUri(request);
return uri.endsWith(request
.getContextPath() + exitUserUrl);
return uri.endsWith(request.getContextPath() + exitUserUrl);
}
/**
@ -449,27 +436,22 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
*
* @see SwitchUserProcessingFilter#switchUserUrl
*/
protected boolean requiresSwitchUser(
HttpServletRequest request) {
protected boolean requiresSwitchUser(HttpServletRequest request) {
String uri = stripUri(request);
return uri.endsWith(request.getContextPath() + switchUserUrl);
}
public void setApplicationEventPublisher(
ApplicationEventPublisher eventPublisher)
throws BeansException {
ApplicationEventPublisher eventPublisher) throws BeansException {
this.eventPublisher = eventPublisher;
}
/**
* Sets the authentication data access object.
*
* @param authenticationDao The authentication dao
*/
public void setUserDetailsService(
UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
public void setAuthenticationDetailsSource(
AuthenticationDetailsSource authenticationDetailsSource) {
Assert.notNull(authenticationDetailsSource,
"AuthenticationDetailsSource required");
this.authenticationDetailsSource = authenticationDetailsSource;
}
/**
@ -477,13 +459,11 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
*
* @param exitUserUrl The exit user URL.
*/
public void setExitUserUrl(
String exitUserUrl) {
public void setExitUserUrl(String exitUserUrl) {
this.exitUserUrl = exitUserUrl;
}
public void setMessageSource(
MessageSource messageSource) {
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
@ -497,16 +477,23 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
}
/**
* Sets the URL to go to after a successful switch / exit user
* request.
* Sets the URL to go to after a successful switch / exit user request.
*
* @param targetUrl The target url.
*/
public void setTargetUrl(
String targetUrl) {
public void setTargetUrl(String targetUrl) {
this.targetUrl = targetUrl;
}
/**
* Sets the authentication data access object.
*
* @param authenticationDao The authentication dao
*/
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
}
/**
* Strips any content after the ';' in the request URI
*
@ -519,8 +506,7 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean,
int idx = uri.indexOf(';');
if (idx > 0) {
uri = uri.substring(0,
idx);
uri = uri.substring(0, idx);
}
return uri;

View File

@ -1,4 +1,4 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,9 +17,10 @@ package org.acegisecurity.ui.webapp;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.AbstractProcessingFilter;
import org.acegisecurity.ui.WebAuthenticationDetails;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
@ -55,15 +56,6 @@ public class AuthenticationProcessingFilter extends AbstractProcessingFilter {
//~ Methods ================================================================
/**
* This filter by default responds to <code>/j_acegi_security_check</code>.
*
* @return the default
*/
public String getDefaultFilterProcessesUrl() {
return "/j_acegi_security_check";
}
public Authentication attemptAuthentication(HttpServletRequest request)
throws AuthenticationException {
String username = obtainUsername(request);
@ -84,28 +76,23 @@ public class AuthenticationProcessingFilter extends AbstractProcessingFilter {
setDetails(request, authRequest);
// Place the last username attempted into HttpSession for views
request.getSession().setAttribute(ACEGI_SECURITY_LAST_USERNAME_KEY,
username);
request.getSession()
.setAttribute(ACEGI_SECURITY_LAST_USERNAME_KEY, username);
return this.getAuthenticationManager().authenticate(authRequest);
}
public void init(FilterConfig filterConfig) throws ServletException {}
/**
* Provided so that subclasses may configure what is put into the
* authentication request's details property. The default implementation
* simply constructs {@link WebAuthenticationDetails}.
* This filter by default responds to <code>/j_acegi_security_check</code>.
*
* @param request that an authentication request is being created for
* @param authRequest the authentication request object that should have
* its details set
* @return the default
*/
protected void setDetails(HttpServletRequest request,
UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(new WebAuthenticationDetails(request, false));
public String getDefaultFilterProcessesUrl() {
return "/j_acegi_security_check";
}
public void init(FilterConfig filterConfig) throws ServletException {}
/**
* Enables subclasses to override the composition of the password, such as
* by including additional values and a separator.
@ -141,4 +128,17 @@ public class AuthenticationProcessingFilter extends AbstractProcessingFilter {
protected String obtainUsername(HttpServletRequest request) {
return request.getParameter(ACEGI_SECURITY_FORM_USERNAME_KEY);
}
/**
* Provided so that subclasses may configure what is put into the
* authentication request's details property.
*
* @param request that an authentication request is being created for
* @param authRequest the authentication request object that should have
* its details set
*/
protected void setDetails(HttpServletRequest request,
UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
}

View File

@ -1,4 +1,4 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,19 +18,24 @@ package org.acegisecurity.ui.x509;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent;
import org.acegisecurity.providers.x509.X509AuthenticationToken;
import org.acegisecurity.ui.AbstractProcessingFilter;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.acegisecurity.ui.AuthenticationDetailsSource;
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.util.Assert;
@ -60,10 +65,11 @@ import javax.servlet.http.HttpServletResponse;
*
* <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.
* 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>
*
* <p>
@ -84,19 +90,11 @@ public class X509ProcessingFilter implements Filter, InitializingBean,
//~ Instance fields ========================================================
private ApplicationEventPublisher eventPublisher;
private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
private AuthenticationManager authenticationManager;
//~ Methods ================================================================
public void setApplicationEventPublisher(ApplicationEventPublisher context) {
this.eventPublisher = context;
}
public void setAuthenticationManager(
AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(authenticationManager,
"An AuthenticationManager must be set");
@ -154,7 +152,8 @@ public class X509ProcessingFilter implements Filter, InitializingBean,
try {
X509AuthenticationToken authRequest = new X509AuthenticationToken(clientCertificate);
authRequest.setDetails(new WebAuthenticationDetails(httpRequest));
authRequest.setDetails(authenticationDetailsSource.buildDetails(
(HttpServletRequest) request));
authResult = authenticationManager.authenticate(authRequest);
successfulAuthentication(httpRequest, httpResponse, authResult);
} catch (AuthenticationException failed) {
@ -165,8 +164,39 @@ public class X509ProcessingFilter implements Filter, InitializingBean,
filterChain.doFilter(request, response);
}
private X509Certificate extractClientCertificate(HttpServletRequest request) {
X509Certificate[] certs = (X509Certificate[]) request.getAttribute(
"javax.servlet.request.X509Certificate");
if ((certs != null) && (certs.length > 0)) {
return certs[0];
}
if (logger.isDebugEnabled()) {
logger.debug("No client certificate found in request.");
}
return null;
}
public void init(FilterConfig ignored) throws ServletException {}
public void setApplicationEventPublisher(ApplicationEventPublisher context) {
this.eventPublisher = context;
}
public void setAuthenticationDetailsSource(
AuthenticationDetailsSource authenticationDetailsSource) {
Assert.notNull(authenticationDetailsSource,
"AuthenticationDetailsSource required");
this.authenticationDetailsSource = authenticationDetailsSource;
}
public void setAuthenticationManager(
AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
/**
* Puts the <code>Authentication</code> instance returned by the
* authentication manager into the secure context.
@ -206,25 +236,12 @@ public class X509ProcessingFilter implements Filter, InitializingBean,
SecurityContextHolder.getContext().setAuthentication(null);
if (logger.isDebugEnabled()) {
logger.debug("Updated SecurityContextHolder to contain null Authentication");
logger.debug(
"Updated SecurityContextHolder to contain null Authentication");
}
request.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY,
request.getSession()
.setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY,
failed);
}
private X509Certificate extractClientCertificate(HttpServletRequest request) {
X509Certificate[] certs = (X509Certificate[]) request.getAttribute(
"javax.servlet.request.X509Certificate");
if ((certs != null) && (certs.length > 0)) {
return certs[0];
}
if (logger.isDebugEnabled()) {
logger.debug("No client certificate found in request.");
}
return null;
}
}

View File

@ -1,4 +1,4 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,8 +18,11 @@ package org.acegisecurity.concurrent;
import junit.framework.TestCase;
import org.acegisecurity.Authentication;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpSession;
@ -33,6 +36,23 @@ import org.springframework.mock.web.MockHttpSession;
public class ConcurrentSessionControllerImplTests extends TestCase {
//~ Methods ================================================================
private Authentication createAuthentication(String user, String password) {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user,
password);
auth.setDetails(createWebDetails(auth));
return auth;
}
private WebAuthenticationDetails createWebDetails(Authentication auth) {
MockHttpSession session = new MockHttpSession();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setSession(session);
request.setUserPrincipal(auth);
return new WebAuthenticationDetails(request);
}
public void testLifecycle() throws Exception {
// Build a test fixture
ConcurrentSessionControllerImpl sc = new ConcurrentSessionControllerImpl();
@ -103,21 +123,4 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
assertTrue(true);
}
}
private Authentication createAuthentication(String user, String password) {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user,
password);
auth.setDetails(createWebDetails(auth));
return auth;
}
private WebAuthenticationDetails createWebDetails(Authentication auth) {
MockHttpSession session = new MockHttpSession();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setSession(session);
request.setUserPrincipal(auth);
return new WebAuthenticationDetails(request, false);
}
}