From 6abceb7ab07b8a8e8816039a4b31d533226cb6d7 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Mon, 20 Feb 2006 00:37:39 +0000 Subject: [PATCH] Additional changes related to SEC-192 (avoiding session creation when creating WebAuthenticationDetails). Also fixed Jalopy chaos in SwitchUserProcessingFilter. --- .../ui/cas/CasProcessingFilter.java | 7 +- .../ui/digestauth/DigestProcessingFilter.java | 7 +- .../SwitchUserProcessingFilter.java | 697 +++++++++--------- .../AuthenticationProcessingFilter.java | 2 +- ...eminderAuthenticationProcessingFilter.java | 2 +- .../ConcurrentSessionControllerImplTests.java | 2 +- 6 files changed, 347 insertions(+), 370 deletions(-) diff --git a/core/src/main/java/org/acegisecurity/ui/cas/CasProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/cas/CasProcessingFilter.java index 79c2352f0d..479edd3ab7 100644 --- a/core/src/main/java/org/acegisecurity/ui/cas/CasProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/cas/CasProcessingFilter.java @@ -102,9 +102,10 @@ public class CasProcessingFilter extends AbstractProcessingFilter { password = ""; } - UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, - password); - authRequest.setDetails(new WebAuthenticationDetails(request)); + UsernamePasswordAuthenticationToken authRequest = + new UsernamePasswordAuthenticationToken(username, password); + + authRequest.setDetails(new WebAuthenticationDetails(request, false)); return this.getAuthenticationManager().authenticate(authRequest); } diff --git a/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java index d429e9d86d..185d735f4a 100644 --- a/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java @@ -369,9 +369,10 @@ public class DigestProcessingFilter implements Filter, InitializingBean, + "' with response: '" + responseDigest + "'"); } - UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(user, - user.getPassword()); - authRequest.setDetails(new WebAuthenticationDetails(httpRequest)); + UsernamePasswordAuthenticationToken authRequest = + new UsernamePasswordAuthenticationToken(user, user.getPassword()); + + authRequest.setDetails(new WebAuthenticationDetails(httpRequest, false)); SecurityContextHolder.getContext().setAuthentication(authRequest); } diff --git a/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java index 2ebf32bafa..4796a635ad 100644 --- a/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java @@ -104,6 +104,10 @@ import org.springframework.util.Assert; * *

* + * + * @author Mark St.Godard + * @version $Id$ + * * @see org.acegisecurity.ui.switchuser.SwitchUserGrantedAuthority */ public class SwitchUserProcessingFilter implements Filter, InitializingBean, @@ -156,10 +160,10 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean, Authentication current = SecurityContextHolder.getContext() .getAuthentication(); - if (null == current) { - throw new AuthenticationCredentialsNotFoundException(messages - .getMessage("SwitchUserProcessingFilter.noCurrentUser", - "No current user associated with this request")); + if (null == current) { + throw new AuthenticationCredentialsNotFoundException(messages + .getMessage("SwitchUserProcessingFilter.noCurrentUser", + "No current user associated with this request")); } // check to see if the current user did actual switch to another user @@ -173,381 +177,352 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean, .getMessage( "SwitchUserProcessingFilter.noOriginalAuthentication", "Could not find original Authentication object")); - } - - // get the source user details - UserDetails originalUser = null; - Object obj = original.getPrincipal(); - - if ((obj != null) && obj instanceof UserDetails) { - originalUser = (UserDetails) obj; - } - - // publish event - if (this.eventPublisher != null) { - eventPublisher.publishEvent(new AuthenticationSwitchUserEvent( - current, originalUser)); - } - - return original; } - /** - * 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 Authentication request if - * successfully switched to another user, - * null otherwise. - * - * @throws AuthenticationException - * @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 - * expired. - * @throws CredentialsExpiredException If the target user - * credentials are expired. - */ - protected Authentication attemptSwitchUser( + // get the source user details + UserDetails originalUser = null; + Object obj = original.getPrincipal(); + + if ((obj != null) && obj instanceof UserDetails) { + originalUser = (UserDetails) obj; + } + + // publish event + if (this.eventPublisher != null) { + eventPublisher.publishEvent(new AuthenticationSwitchUserEvent( + current, originalUser)); + } + + return original; + } + + /** + * 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 Authentication request if + * successfully switched to another user, + * null otherwise. + * + * @throws AuthenticationException + * @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 + * expired. + * @throws CredentialsExpiredException If the target user + * credentials are expired. + */ + protected Authentication attemptSwitchUser( HttpServletRequest request) throws AuthenticationException { - UsernamePasswordAuthenticationToken targetUserRequest = null; + UsernamePasswordAuthenticationToken targetUserRequest = null; - String username = request.getParameter(ACEGI_SECURITY_SWITCH_USERNAME_KEY); + String username = request.getParameter(ACEGI_SECURITY_SWITCH_USERNAME_KEY); - if (username == null) { - username = ""; + if (username == null) { + username = ""; + } + + if (logger.isDebugEnabled()) { + logger.debug("Attempt to switch to user [" + username + "]"); + } + + // load the user by name + 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")); + } + + // account is expired + if (!targetUser.isAccountNonLocked()) { + throw new LockedException(messages.getMessage( + "SwitchUserProcessingFilter.locked", + "User account is locked")); + } + + // user is disabled + if (!targetUser.isEnabled()) { + throw new DisabledException(messages.getMessage( + "SwitchUserProcessingFilter.disabled", + "User is disabled")); + } + + // account is expired + if (!targetUser.isAccountNonExpired()) { + throw new AccountExpiredException(messages.getMessage( + "SwitchUserProcessingFilter.expired", + "User account has expired")); + } + + // credentials expired + if (!targetUser.isCredentialsNonExpired()) { + throw new CredentialsExpiredException(messages + .getMessage( + "SwitchUserProcessingFilter.credentialsExpired", + "User credentials have expired")); + } + + // ok, create the switch user token + targetUserRequest = createSwitchUserToken(request, + username, targetUser); + + if (logger.isDebugEnabled()) { + logger.debug("Switch User Token [" + targetUserRequest + "]"); + } + + // publish event + if (this.eventPublisher != null) { + eventPublisher.publishEvent(new AuthenticationSwitchUserEvent( + SecurityContextHolder.getContext().getAuthentication(), + targetUser)); + } + + return targetUserRequest; + } + + /** + * Create a switch user token that contains an additional + * GrantedAuthority that contains the original + * Authentication object. + * + * @param request The http servlet request. + * @param username The username of target user + * @param targetUser The target user + * + * @return The authentication token + * + * @see SwitchUserGrantedAuthority + */ + private UsernamePasswordAuthenticationToken createSwitchUserToken( + HttpServletRequest request, String username, + UserDetails targetUser) { + UsernamePasswordAuthenticationToken targetUserRequest; + + // grant an additional authority that contains the original Authentication object + // which will be used to 'exit' from the current switched user. + Authentication currentAuth = SecurityContextHolder.getContext() + .getAuthentication(); + GrantedAuthority switchAuthority = new SwitchUserGrantedAuthority(ROLE_PREVIOUS_ADMINISTRATOR, + currentAuth); + + // get the original authorities + List orig = Arrays.asList(targetUser.getAuthorities()); + + // add the new switch user authority + List newAuths = new ArrayList(orig); + newAuths.add(switchAuthority); + + GrantedAuthority[] authorities = {}; + authorities = (GrantedAuthority[]) newAuths.toArray(authorities); + + // create the new authentication token + targetUserRequest = new UsernamePasswordAuthenticationToken(targetUser, + targetUser.getPassword(), authorities); + + // set details + targetUserRequest.setDetails(new WebAuthenticationDetails( + request, false)); + + return targetUserRequest; + } + + public void destroy() {} + + /** + * @see javax.servlet.Filter#doFilter + */ + public void doFilter(ServletRequest request, + ServletResponse response, FilterChain chain) + throws IOException, ServletException { + Assert.isInstanceOf(HttpServletRequest.class, request); + Assert.isInstanceOf(HttpServletResponse.class, response); + + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + + // check for switch or exit request + if (requiresSwitchUser(httpRequest)) { + // if set, attempt switch and store original + Authentication targetUser = attemptSwitchUser(httpRequest); + + // update the current context to the new target user + SecurityContextHolder.getContext() + .setAuthentication(targetUser); + + // redirect to target url + httpResponse.sendRedirect(httpResponse + .encodeRedirectURL(httpRequest + .getContextPath() + targetUrl)); + + return; + } else if (requiresExitUser(httpRequest)) { + // get the original authentication object (if exists) + Authentication originalUser = attemptExitUser(httpRequest); + + // update the current context back to the original user + SecurityContextHolder.getContext() + .setAuthentication(originalUser); + + // redirect to target url + httpResponse.sendRedirect(httpResponse.encodeRedirectURL( + httpRequest.getContextPath() + targetUrl)); + + return; + } + + chain.doFilter(request, response); + } + + /** + * Find the original Authentication object from + * the current user's granted authorities. A successfully switched + * user should have a SwitchUserGrantedAuthority + * that contains the original source user Authentication + * object. + * + * @param current The current Authentication + * object + * + * @return The source user Authentication + * object or null otherwise. + */ + private Authentication getSourceAuthentication( + Authentication current) { + Authentication original = null; + + // iterate over granted authorities and find the 'switch user' authority + 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 [" + + original + "]"); } + } - if (logger.isDebugEnabled()) { - logger.debug("Attempt to switch to user [" + username + "]"); - } + return original; + } - // load the user by name - UserDetails targetUser = this.userDetailsService - .loadUserByUsername(username); + public void init(FilterConfig ignored) + throws ServletException {} - // user not found - if (targetUser == null) { - throw new UsernameNotFoundException(messages.getMessage( - "SwitchUserProcessingFilter.usernameNotFound", - new Object[] {username}, - "Username {0} not found")); - } + /** + * Checks the request URI for the presence + * of exitUserUrl. + * + * @param request The http servlet request + * + * @return true if the request requires a exit user, + * false otherwise. + * + * @see SwitchUserProcessingFilter#exitUserUrl + */ + protected boolean requiresExitUser( + HttpServletRequest request) { + String uri = stripUri(request); - // account is expired - if (!targetUser.isAccountNonLocked()) { - throw new LockedException(messages.getMessage( - "SwitchUserProcessingFilter.locked", - "User account is locked")); - } + return uri.endsWith(request + .getContextPath() + exitUserUrl); + } - // user is disabled - if (!targetUser.isEnabled()) { - throw new DisabledException(messages.getMessage( - "SwitchUserProcessingFilter.disabled", - "User is disabled")); - } + /** + * Checks the request URI for the presence of switchUserUrl. + * + * @param request The http servlet request + * + * @return true if the request requires a switch, + * false otherwise. + * + * @see SwitchUserProcessingFilter#switchUserUrl + */ + protected boolean requiresSwitchUser( + HttpServletRequest request) { + String uri = stripUri(request); - // account is expired - if (!targetUser.isAccountNonExpired()) { - throw new AccountExpiredException(messages.getMessage( - "SwitchUserProcessingFilter.expired", - "User account has expired")); - } + return uri.endsWith(request.getContextPath() + switchUserUrl); + } - // credentials expired - if (!targetUser.isCredentialsNonExpired()) { - throw new CredentialsExpiredException(messages - .getMessage( - "SwitchUserProcessingFilter.credentialsExpired", - "User credentials have expired")); - } + public void setApplicationEventPublisher( + ApplicationEventPublisher eventPublisher) + throws BeansException { + this.eventPublisher = eventPublisher; + } - // ok, create the switch user token - targetUserRequest = createSwitchUserToken(request, - username, targetUser); + /** + * Sets the authentication data access object. + * + * @param authenticationDao The authentication dao + */ + public void setUserDetailsService( + UserDetailsService authenticationDao) { + this.userDetailsService = authenticationDao; + } - if (logger.isDebugEnabled()) { - logger.debug("Switch User Token [" - + targetUserRequest + "]"); - } + /** + * Set the URL to respond to exit user processing. + * + * @param exitUserUrl The exit user URL. + */ + public void setExitUserUrl( + String exitUserUrl) { + this.exitUserUrl = exitUserUrl; + } - // publish event - if (this.eventPublisher != null) { - eventPublisher.publishEvent(new AuthenticationSwitchUserEvent( - SecurityContextHolder.getContext() - .getAuthentication(), - targetUser)); - } + public void setMessageSource( + MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } - return targetUserRequest; - } + /** + * Set the URL to respond to switch user processing. + * + * @param switchUserUrl The switch user URL. + */ + public void setSwitchUserUrl(String switchUserUrl) { + this.switchUserUrl = switchUserUrl; + } - /** - * Create a switch user token that contains an additional - * GrantedAuthority that contains the original - * Authentication object. - * - * @param request The http servlet request. - * @param username The username of target user - * @param targetUser The target user - * - * @return The authentication token - * - * @see SwitchUserGrantedAuthority - */ - private UsernamePasswordAuthenticationToken createSwitchUserToken( - HttpServletRequest request, String username, - UserDetails targetUser) { - UsernamePasswordAuthenticationToken targetUserRequest; + /** + * Sets the URL to go to after a successful switch / exit user + * request. + * + * @param targetUrl The target url. + */ + public void setTargetUrl( + String targetUrl) { + this.targetUrl = targetUrl; + } - // grant an additional authority that contains the original Authentication object - // which will be used to 'exit' from the current switched user. - Authentication currentAuth = SecurityContextHolder.getContext() - .getAuthentication(); - GrantedAuthority switchAuthority = new SwitchUserGrantedAuthority(ROLE_PREVIOUS_ADMINISTRATOR, - currentAuth); + /** + * Strips any content after the ';' in the request URI + * + * @param request The http request + * + * @return The stripped uri + */ + private static String stripUri(HttpServletRequest request) { + String uri = request.getRequestURI(); + int idx = uri.indexOf(';'); - // get the original authorities - List orig = Arrays.asList(targetUser.getAuthorities()); + if (idx > 0) { + uri = uri.substring(0, + idx); + } - // add the new switch user authority - List newAuths = new ArrayList(orig); - newAuths.add(switchAuthority); - - GrantedAuthority[] authorities = {}; - authorities = (GrantedAuthority[]) newAuths.toArray(authorities); - - // create the new authentication token - targetUserRequest = new UsernamePasswordAuthenticationToken(targetUser, - targetUser.getPassword(), authorities); - - // set details - targetUserRequest.setDetails(new WebAuthenticationDetails( - request)); - - return targetUserRequest; - } - - public void destroy() {} - - /** - * @see javax.servlet.Filter#doFilter - */ - public void doFilter(ServletRequest request, - ServletResponse response, FilterChain chain) - throws IOException, ServletException { - Assert.isInstanceOf(HttpServletRequest.class, request); - Assert.isInstanceOf(HttpServletResponse.class, response); - - HttpServletRequest httpRequest = (HttpServletRequest) request; - HttpServletResponse httpResponse = (HttpServletResponse) response; - - // check for switch or exit request - if (requiresSwitchUser(httpRequest)) { - // if set, attempt switch and store original - Authentication targetUser = attemptSwitchUser(httpRequest); - - // update the current context to the new target user - SecurityContextHolder.getContext() - .setAuthentication(targetUser); - - // redirect to target url - httpResponse.sendRedirect(httpResponse - .encodeRedirectURL(httpRequest - .getContextPath() + targetUrl)); - - return; - } else if (requiresExitUser(httpRequest)) { - // get the original authentication object (if exists) - Authentication originalUser = attemptExitUser(httpRequest); - - // update the current context back to the original user - SecurityContextHolder.getContext() - .setAuthentication(originalUser); - - // redirect to target url - httpResponse.sendRedirect(httpResponse - .encodeRedirectURL(httpRequest - .getContextPath() - + targetUrl)); - - return; - } - - chain.doFilter(request, response); - } - - /** - * Find the original - * Authentication object from - * the current user's granted authorities. - * A successfully switched user should - * have a - * SwitchUserGrantedAuthority - * that contains the original source user - * Authentication object. - * - * @param current The current - * Authentication - * object - * - * @return The source user - * Authentication - * object or null - * otherwise. - */ - private Authentication getSourceAuthentication( - Authentication current) { - Authentication original = null; - - // iterate over granted authorities and find the 'switch user' authority - 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 [" - + original + "]"); - } - } - - return original; - } - - public void init(FilterConfig ignored) - throws ServletException {} - - /** - * Checks the request URI for the presence - * of exitUserUrl. - * - * @param request The http servlet request - * - * @return true if the request - * requires a exit user, - * false otherwise. - * - * @see SwitchUserProcessingFilter#exitUserUrl - */ - protected boolean requiresExitUser( - HttpServletRequest request) { - String uri = stripUri(request); - - return uri.endsWith(request - .getContextPath() + exitUserUrl); - } - - /** - * Checks the request URI for the - * presence of switchUserUrl. - * - * @param request The http servlet - * request - * - * @return true if the - * request requires a switch, - * false - * otherwise. - * - * @see SwitchUserProcessingFilter#switchUserUrl - */ - protected boolean requiresSwitchUser( - HttpServletRequest request) { - String uri = stripUri(request); - - return uri.endsWith(request - .getContextPath() - + switchUserUrl); - } - - public void setApplicationEventPublisher( - 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; - } - - /** - * Set the URL to respond to exit - * user processing. - * - * @param exitUserUrl The exit user - * URL. - */ - public void setExitUserUrl( - String exitUserUrl) { - this.exitUserUrl = exitUserUrl; - } - - public void setMessageSource( - MessageSource messageSource) { - this.messages = new MessageSourceAccessor(messageSource); - } - - /** - * Set the URL to respond to switch - * user processing. - * - * @param switchUserUrl The switch - * user URL. - */ - public void setSwitchUserUrl( - String switchUserUrl) { - this.switchUserUrl = switchUserUrl; - } - - /** - * Sets the URL to go to after a - * successful switch / exit user - * request. - * - * @param targetUrl The target url. - */ - public void setTargetUrl( - String targetUrl) { - this.targetUrl = targetUrl; - } - - /** - * Strips any content after the ';' - * in the request URI - * - * @param request The http request - * - * @return The stripped uri - */ - private static String stripUri( - HttpServletRequest request) { - String uri = request - .getRequestURI(); - int idx = uri.indexOf(';'); - - if (idx > 0) { - uri = uri.substring(0, - idx); - } - - return uri; - } - } + return uri; + } +} diff --git a/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilter.java index 8fdd24705f..1e8b9e233b 100644 --- a/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilter.java @@ -103,7 +103,7 @@ public class AuthenticationProcessingFilter extends AbstractProcessingFilter { */ protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) { - authRequest.setDetails(new WebAuthenticationDetails(request)); + authRequest.setDetails(new WebAuthenticationDetails(request, false)); } /** diff --git a/core/src/main/java/org/acegisecurity/ui/webapp/SiteminderAuthenticationProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/webapp/SiteminderAuthenticationProcessingFilter.java index 4c83ead8f8..f0718da47e 100644 --- a/core/src/main/java/org/acegisecurity/ui/webapp/SiteminderAuthenticationProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/webapp/SiteminderAuthenticationProcessingFilter.java @@ -240,7 +240,7 @@ public class SiteminderAuthenticationProcessingFilter */ protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) { - authRequest.setDetails(new WebAuthenticationDetails(request)); + authRequest.setDetails(new WebAuthenticationDetails(request, false)); } /** diff --git a/core/src/test/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImplTests.java b/core/src/test/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImplTests.java index 261ca7f2e6..89adc33e83 100644 --- a/core/src/test/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImplTests.java +++ b/core/src/test/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImplTests.java @@ -118,6 +118,6 @@ public class ConcurrentSessionControllerImplTests extends TestCase { request.setSession(session); request.setUserPrincipal(auth); - return new WebAuthenticationDetails(request); + return new WebAuthenticationDetails(request, false); } }