Added initial integration of SEC-29 "Save POST request parameters before redirect" for peer review. See http://opensource2.atlassian.com/projects/spring/browse/SEC-29 for more info.
This commit is contained in:
parent
f2019ca3ba
commit
a8ad9231ab
|
@ -0,0 +1,308 @@
|
||||||
|
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package net.sf.acegisecurity.intercept.web;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.AccessDeniedException;
|
||||||
|
import net.sf.acegisecurity.AuthenticationException;
|
||||||
|
import net.sf.acegisecurity.AuthenticationTrustResolver;
|
||||||
|
import net.sf.acegisecurity.AuthenticationTrustResolverImpl;
|
||||||
|
import net.sf.acegisecurity.InsufficientAuthenticationException;
|
||||||
|
import net.sf.acegisecurity.context.SecurityContextHolder;
|
||||||
|
import net.sf.acegisecurity.ui.AbstractProcessingFilter;
|
||||||
|
import net.sf.acegisecurity.util.PortResolver;
|
||||||
|
import net.sf.acegisecurity.util.PortResolverImpl;
|
||||||
|
import net.sf.acegisecurity.wrapper.redirect.SavedHttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps requests to the {@link FilterSecurityInterceptor}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This filter is necessary because it provides the bridge between incoming
|
||||||
|
* requests and the <code>FilterSecurityInterceptor</code> instance.
|
||||||
|
* </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
|
||||||
|
* net.sf.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 respond with a
|
||||||
|
* <code>HttpServletResponse.SC_FORBIDDEN</code> (403 error). In addition,
|
||||||
|
* the <code>AccessDeniedException</code> itself will be placed in the
|
||||||
|
* <code>HttpSession</code> attribute keyed against {@link
|
||||||
|
* #ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY} (to allow access to the stack
|
||||||
|
* trace etc). Again, this allows common access denied handling irrespective
|
||||||
|
* of the originating security interceptor.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* To use this filter, it is necessary to specify the following properties:
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>
|
||||||
|
* <code>filterSecurityInterceptor</code> indicates the
|
||||||
|
* <code>FilterSecurityInterceptor</code> to delegate HTTP security decisions
|
||||||
|
* to.
|
||||||
|
* </li>
|
||||||
|
* <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
|
||||||
|
* net.sf.acegisecurity.util.FilterToBeanProxy}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @author colin sampaleanu
|
||||||
|
* @author Andrey Grebnev <a href="mailto:andrey.grebnev@blandware.com"><andrey.grebnev@blandware.com></a>
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class SandboxSecurityEnforcementFilter implements Filter, InitializingBean {
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(SecurityEnforcementFilter.class);
|
||||||
|
|
||||||
|
public static final String ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY = "ACEGI_SECURITY_403_EXCEPTION";
|
||||||
|
public static final String SAVED_REQUEST_SESSION_ATTRIBUTE = "net.sf.acegisecurity.intercept.web.SAVED_REQUEST_SESSION_ATTRIBUTE";
|
||||||
|
|
||||||
|
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||||
|
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
||||||
|
private FilterSecurityInterceptor filterSecurityInterceptor;
|
||||||
|
private PortResolver portResolver = new PortResolverImpl();
|
||||||
|
private boolean createSessionAllowed = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the AuthenticationEntryPoint.
|
||||||
|
* @param authenticationEntryPoint The authentication entry point.
|
||||||
|
*/
|
||||||
|
public void setAuthenticationEntryPoint(
|
||||||
|
AuthenticationEntryPoint authenticationEntryPoint) {
|
||||||
|
this.authenticationEntryPoint = authenticationEntryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the AuthenticationEntryPoint.
|
||||||
|
* @return The authentication entry point.
|
||||||
|
*/
|
||||||
|
public AuthenticationEntryPoint getAuthenticationEntryPoint() {
|
||||||
|
return authenticationEntryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the AuthenticationTrustResolver.
|
||||||
|
* @param authenticationTrustResolver The AuthenticationTrustResolver.
|
||||||
|
*/
|
||||||
|
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 net.sf.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationTrustResolver getAuthenticationTrustResolver() {
|
||||||
|
return authenticationTrustResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilterSecurityInterceptor(
|
||||||
|
FilterSecurityInterceptor filterSecurityInterceptor) {
|
||||||
|
this.filterSecurityInterceptor = filterSecurityInterceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilterSecurityInterceptor getFilterSecurityInterceptor() {
|
||||||
|
return filterSecurityInterceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPortResolver(PortResolver portResolver) {
|
||||||
|
this.portResolver = portResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortResolver getPortResolver() {
|
||||||
|
return portResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
Assert.notNull(authenticationEntryPoint,
|
||||||
|
"authenticationEntryPoint must be specified");
|
||||||
|
Assert.notNull(filterSecurityInterceptor,
|
||||||
|
"filterSecurityInterceptor must be specified");
|
||||||
|
Assert.notNull(portResolver, "portResolver must be specified");
|
||||||
|
Assert.notNull(authenticationTrustResolver,
|
||||||
|
"authenticationTrustResolver must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain chain) throws IOException, ServletException {
|
||||||
|
if (!(request instanceof HttpServletRequest)) {
|
||||||
|
throw new ServletException("HttpServletRequest required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(response instanceof HttpServletResponse)) {
|
||||||
|
throw new ServletException("HttpServletResponse required");
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterInvocation fi = new FilterInvocation(request, response, chain);
|
||||||
|
|
||||||
|
try {
|
||||||
|
filterSecurityInterceptor.invoke(fi);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Chain processed normally");
|
||||||
|
}
|
||||||
|
} catch (AuthenticationException authentication) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Authentication exception occurred; redirecting to authentication entry point",
|
||||||
|
authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendStartAuthentication(fi, authentication);
|
||||||
|
} catch (AccessDeniedException accessDenied) {
|
||||||
|
if (authenticationTrustResolver.isAnonymous(
|
||||||
|
SecurityContextHolder.getContext().getAuthentication())) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point",
|
||||||
|
accessDenied);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendStartAuthentication(fi,
|
||||||
|
new InsufficientAuthenticationException(
|
||||||
|
"Full authentication is required to access this resource"));
|
||||||
|
} else {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Access is denied (user is not anonymous); sending back forbidden response",
|
||||||
|
accessDenied);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendAccessDeniedError(fi, accessDenied);
|
||||||
|
}
|
||||||
|
} catch (ServletException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Throwable otherException) {
|
||||||
|
throw new ServletException(otherException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sendAccessDeniedError(FilterInvocation fi,
|
||||||
|
AccessDeniedException accessDenied)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
if (createSessionAllowed) {
|
||||||
|
((HttpServletRequest) fi.getRequest()).getSession().setAttribute(ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY,
|
||||||
|
accessDenied);
|
||||||
|
}
|
||||||
|
|
||||||
|
((HttpServletResponse) fi.getResponse()).sendError(HttpServletResponse.SC_FORBIDDEN,
|
||||||
|
accessDenied.getMessage()); // 403
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sendStartAuthentication(FilterInvocation fi,
|
||||||
|
AuthenticationException reason) throws ServletException, IOException {
|
||||||
|
|
||||||
|
// Get the HttpServletRequest
|
||||||
|
HttpServletRequest request = (HttpServletRequest) fi.getRequest();
|
||||||
|
|
||||||
|
// Save this original request on the session in case
|
||||||
|
// SecurityContextHolderAwareRequestWrapper has to resume it after (re)authentication.
|
||||||
|
request.getSession().setAttribute(SAVED_REQUEST_SESSION_ATTRIBUTE, SavedHttpServletRequest.saveRequest(request));
|
||||||
|
|
||||||
|
int port = portResolver.getServerPort(request);
|
||||||
|
boolean includePort = true;
|
||||||
|
|
||||||
|
if ("http".equals(request.getScheme().toLowerCase()) && (port == 80)) {
|
||||||
|
includePort = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("https".equals(request.getScheme().toLowerCase()) && (port == 443)) {
|
||||||
|
includePort = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the target URL from the request
|
||||||
|
String targetUrl = request.getScheme() + "://" +
|
||||||
|
request.getServerName() + ((includePort) ? (":" + port) : "") +
|
||||||
|
request.getContextPath() + fi.getRequestUrl();
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"Authentication entry point being called; target URL added to Session: " +
|
||||||
|
targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createSessionAllowed) {
|
||||||
|
((HttpServletRequest) request).getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY,
|
||||||
|
targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticationEntryPoint.commence(request,
|
||||||
|
(HttpServletResponse) fi.getResponse(), reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,475 @@
|
||||||
|
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.sf.acegisecurity.wrapper;
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import javax.servlet.http.Cookie;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.AuthenticationTrustResolver;
|
||||||
|
import net.sf.acegisecurity.AuthenticationTrustResolverImpl;
|
||||||
|
import net.sf.acegisecurity.GrantedAuthority;
|
||||||
|
import net.sf.acegisecurity.UserDetails;
|
||||||
|
import net.sf.acegisecurity.context.SecurityContextHolder;
|
||||||
|
import net.sf.acegisecurity.intercept.web.SandboxSecurityEnforcementFilter;
|
||||||
|
import net.sf.acegisecurity.wrapper.redirect.Enumerator;
|
||||||
|
import net.sf.acegisecurity.wrapper.redirect.FastHttpDateFormat;
|
||||||
|
import net.sf.acegisecurity.wrapper.redirect.SavedHttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Acegi Security-aware <code>HttpServletRequestWrapper</code>, which uses
|
||||||
|
* the <code>SecurityContext</code>-defined <code>Authentication</code>
|
||||||
|
* object for
|
||||||
|
* {@link SecurityContextHolderAwareRequestWrapper#isUserInRole(java.lang.String)}
|
||||||
|
* and {@link javax.servlet.http.HttpServletRequestWrapper#getRemoteUser()}
|
||||||
|
* responses.
|
||||||
|
* <p>
|
||||||
|
* Provides request parameters, headers, cookies from original requrest or saved request.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Orlando Garcia Carmona
|
||||||
|
* @author Ben Alex
|
||||||
|
* @author Andrey Grebnev <a href="mailto:andrey.grebnev@blandware.com"><andrey.grebnev@blandware.com></a>
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class SandboxSecurityContextHolderAwareRequestWrapper extends
|
||||||
|
HttpServletRequestWrapper {
|
||||||
|
|
||||||
|
// ~ Static fields ========================================================
|
||||||
|
|
||||||
|
protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default Locale if none are specified.
|
||||||
|
*/
|
||||||
|
protected static Locale defaultLocale = Locale.getDefault();
|
||||||
|
|
||||||
|
// ~ Instance fields
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication trust resolver.
|
||||||
|
*/
|
||||||
|
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of SimpleDateFormat formats to use in getDateHeader().
|
||||||
|
*
|
||||||
|
* Notice that because SimpleDateFormat is not thread-safe, we can't declare
|
||||||
|
* formats[] as a static variable.
|
||||||
|
*/
|
||||||
|
protected SimpleDateFormat formats[] = new SimpleDateFormat[3];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saved request (to be resumed after authentication)
|
||||||
|
*/
|
||||||
|
protected SavedHttpServletRequest savedRequest = null;
|
||||||
|
|
||||||
|
// ~ Constructors
|
||||||
|
// ===========================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class' primary constructor.
|
||||||
|
*
|
||||||
|
* @param request HttpServletRequest
|
||||||
|
*/
|
||||||
|
public SandboxSecurityContextHolderAwareRequestWrapper(HttpServletRequest request) {
|
||||||
|
|
||||||
|
// First do what the parent class needs to.
|
||||||
|
super(request);
|
||||||
|
|
||||||
|
// Return if there isn't an existing HttpSession
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
if (session != null) {
|
||||||
|
|
||||||
|
// We know there's an existing HttpSession, so see if it has a
|
||||||
|
// saved request (placed there by SecurityEnforcementFilter).
|
||||||
|
SavedHttpServletRequest saved = (SavedHttpServletRequest) session
|
||||||
|
.getAttribute(SandboxSecurityEnforcementFilter.SAVED_REQUEST_SESSION_ATTRIBUTE);
|
||||||
|
if (saved != null) {
|
||||||
|
|
||||||
|
// We know there's a saved request, so see if it has a
|
||||||
|
// saved "root" request URI to forward to.
|
||||||
|
String requestURI = saved.getRequestURI();
|
||||||
|
if (requestURI != null) {
|
||||||
|
|
||||||
|
// We know there's a saved "root" request URI, so see if
|
||||||
|
// it's the
|
||||||
|
// same one specified by this request.
|
||||||
|
if (requestURI.equals(request.getRequestURI())) {
|
||||||
|
|
||||||
|
// They're the same "root" request URIs, so get the
|
||||||
|
// saved request and remove it from the HttpSession
|
||||||
|
// since we only want to process it once.
|
||||||
|
savedRequest = saved;
|
||||||
|
session
|
||||||
|
.removeAttribute(SandboxSecurityEnforcementFilter.SAVED_REQUEST_SESSION_ATTRIBUTE);
|
||||||
|
|
||||||
|
formats[0] = new SimpleDateFormat(
|
||||||
|
"EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
|
||||||
|
formats[1] = new SimpleDateFormat(
|
||||||
|
"EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US);
|
||||||
|
formats[2] = new SimpleDateFormat(
|
||||||
|
"EEE MMMM d HH:mm:ss yyyy", Locale.US);
|
||||||
|
|
||||||
|
formats[0].setTimeZone(GMT_ZONE);
|
||||||
|
formats[1].setTimeZone(GMT_ZONE);
|
||||||
|
formats[2].setTimeZone(GMT_ZONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~ Methods
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the principal's name, as obtained from the
|
||||||
|
* <code>SecurityContextHolder</code>. Properly handles both
|
||||||
|
* <code>String</code>-based and <code>UserDetails</code>-based
|
||||||
|
* principals.
|
||||||
|
*
|
||||||
|
* @return the username or <code>null</code> if unavailable
|
||||||
|
*/
|
||||||
|
public String getRemoteUser() {
|
||||||
|
Authentication auth = getAuthentication();
|
||||||
|
|
||||||
|
if ((auth == null) || (auth.getPrincipal() == null)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth.getPrincipal() instanceof UserDetails) {
|
||||||
|
return ((UserDetails) auth.getPrincipal()).getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
return auth.getPrincipal().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple searches for an exactly matching {@link
|
||||||
|
* GrantedAuthority#getAuthority()}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Will always return <code>false</code> if the
|
||||||
|
* <code>SecurityContextHolder</code> contains an
|
||||||
|
* <code>Authentication</code> with
|
||||||
|
* <code>null</code><code>principal</code> and/or
|
||||||
|
* <code>GrantedAuthority[]</code> objects.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param role the <code>GrantedAuthority</code><code>String</code> representation to check for.
|
||||||
|
* @return <code>true</code> if an <b>exact</b> (case sensitive) matching granted authority is located, <code>false</code> otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isUserInRole(String role) {
|
||||||
|
return isGranted(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the <code>Authentication</code> (which is a subclass of
|
||||||
|
* <code>Principal</code>), or <code>null</code> if unavailable.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Note: Override this method in order to workaround the problem in Sun Java
|
||||||
|
* System Application Server 8.1 PE
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return the <code>Authentication</code>, or <code>null</code>
|
||||||
|
*/
|
||||||
|
public Principal getUserPrincipal() {
|
||||||
|
Authentication auth = getAuthentication();
|
||||||
|
|
||||||
|
if ((auth == null) || (auth.getPrincipal() == null)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the current active <code>Authentication</code>
|
||||||
|
*
|
||||||
|
* @return the authentication object or <code>null</code>
|
||||||
|
*/
|
||||||
|
private Authentication getAuthentication() {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext()
|
||||||
|
.getAuthentication();
|
||||||
|
|
||||||
|
if (!authenticationTrustResolver.isAnonymous(auth)) {
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if principal has been granted a given role.
|
||||||
|
*
|
||||||
|
* @param role The role being tested.
|
||||||
|
* @return True if principal has been granted the given role.
|
||||||
|
*/
|
||||||
|
private boolean isGranted(String role) {
|
||||||
|
Authentication auth = getAuthentication();
|
||||||
|
|
||||||
|
if ((auth == null) || (auth.getPrincipal() == null)
|
||||||
|
|| (auth.getAuthorities() == null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < auth.getAuthorities().length; i++) {
|
||||||
|
if (role.equals(auth.getAuthorities()[i].getAuthority())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getMethod() on the
|
||||||
|
* wrapped request object.
|
||||||
|
*/
|
||||||
|
public String getMethod() {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getMethod();
|
||||||
|
} else {
|
||||||
|
return savedRequest.getMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getHeader(String name)
|
||||||
|
* on the wrapped request object.
|
||||||
|
*/
|
||||||
|
public String getHeader(String name) {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getHeader(name);
|
||||||
|
} else {
|
||||||
|
String header = null;
|
||||||
|
Iterator iterator = savedRequest.getHeaderValues(name);
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
header = (String) iterator.next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getIntHeader(String
|
||||||
|
* name) on the wrapped request object.
|
||||||
|
*/
|
||||||
|
public int getIntHeader(String name) {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getIntHeader(name);
|
||||||
|
} else {
|
||||||
|
String value = getHeader(name);
|
||||||
|
if (value == null) {
|
||||||
|
return (-1);
|
||||||
|
} else {
|
||||||
|
return (Integer.parseInt(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getDateHeader(String
|
||||||
|
* name) on the wrapped request object.
|
||||||
|
*/
|
||||||
|
public long getDateHeader(String name) {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getDateHeader(name);
|
||||||
|
} else {
|
||||||
|
String value = getHeader(name);
|
||||||
|
if (value == null)
|
||||||
|
return (-1L);
|
||||||
|
|
||||||
|
// Attempt to convert the date header in a variety of formats
|
||||||
|
long result = FastHttpDateFormat.parseDate(value, formats);
|
||||||
|
if (result != (-1L)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getHeaderNames() on the
|
||||||
|
* wrapped request object.
|
||||||
|
*/
|
||||||
|
public Enumeration getHeaderNames() {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getHeaderNames();
|
||||||
|
} else {
|
||||||
|
return new Enumerator(savedRequest.getHeaderNames());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getHeaders(String name)
|
||||||
|
* on the wrapped request object.
|
||||||
|
*/
|
||||||
|
public Enumeration getHeaders(String name) {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getHeaders(name);
|
||||||
|
} else {
|
||||||
|
return new Enumerator(savedRequest.getHeaderValues(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getCookies() on the
|
||||||
|
* wrapped request object.
|
||||||
|
*/
|
||||||
|
public Cookie[] getCookies() {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getCookies();
|
||||||
|
} else {
|
||||||
|
List cookies = savedRequest.getCookies();
|
||||||
|
return (Cookie[]) cookies.toArray(new Cookie[cookies.size()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return
|
||||||
|
* getParameterValues(String name) on the wrapped request object.
|
||||||
|
*/
|
||||||
|
public String[] getParameterValues(String name) {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getParameterValues(name);
|
||||||
|
} else {
|
||||||
|
return savedRequest.getParameterValues(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getParameterNames() on
|
||||||
|
* the wrapped request object.
|
||||||
|
*/
|
||||||
|
public Enumeration getParameterNames() {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getParameterNames();
|
||||||
|
} else {
|
||||||
|
return new Enumerator(savedRequest.getParameterNames());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getParameterMap() on the
|
||||||
|
* wrapped request object.
|
||||||
|
*/
|
||||||
|
public Map getParameterMap() {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getParameterMap();
|
||||||
|
} else {
|
||||||
|
return savedRequest.getParameterMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getParameter(String
|
||||||
|
* name) on the wrapped request object.
|
||||||
|
*/
|
||||||
|
public String getParameter(String name) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if (savedRequest == null) { return super.getParameter(name); } else {
|
||||||
|
* String value = null; String[] values =
|
||||||
|
* savedRequest.getParameterValues(name); if (values == null) return
|
||||||
|
* null; for (int i = 0; i < values.length; i++) { value = values[i];
|
||||||
|
* break; } return value; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// We do not get value from super.getParameter because
|
||||||
|
// of a bug in Jetty servlet-container.
|
||||||
|
String value = null;
|
||||||
|
String[] values = null;
|
||||||
|
if (savedRequest == null) {
|
||||||
|
values = super.getParameterValues(name);
|
||||||
|
} else {
|
||||||
|
values = savedRequest.getParameterValues(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values == null)
|
||||||
|
return null;
|
||||||
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
value = values[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getLocales() on the
|
||||||
|
* wrapped request object.
|
||||||
|
*/
|
||||||
|
public Enumeration getLocales() {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getLocales();
|
||||||
|
} else {
|
||||||
|
Iterator iterator = savedRequest.getLocales();
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
return new Enumerator(iterator);
|
||||||
|
} else {
|
||||||
|
ArrayList results = new ArrayList();
|
||||||
|
results.add(defaultLocale);
|
||||||
|
return new Enumerator(results.iterator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default behavior of this method is to return getLocale() on the
|
||||||
|
* wrapped request object.
|
||||||
|
*/
|
||||||
|
public Locale getLocale() {
|
||||||
|
if (savedRequest == null) {
|
||||||
|
return super.getLocale();
|
||||||
|
} else {
|
||||||
|
Locale locale = null;
|
||||||
|
Iterator iterator = savedRequest.getLocales();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
locale = (Locale) iterator.next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (locale == null) {
|
||||||
|
return defaultLocale;
|
||||||
|
} else {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.sf.acegisecurity.wrapper.redirect;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adapter class that wraps an <code>Enumeration</code> around a Java2
|
||||||
|
* collection classes object <code>Iterator</code> so that existing APIs
|
||||||
|
* returning Enumerations can easily run on top of the new collections.
|
||||||
|
* Constructors are provided to easliy create such wrappers.</p>
|
||||||
|
* <p>The source code is taken from Apache Tomcat</p>
|
||||||
|
*
|
||||||
|
* <p><a href="Enumerator.java.html"><i>View Source</i></a></p>
|
||||||
|
*
|
||||||
|
* @author Craig R. McClanahan
|
||||||
|
* @author Andrey Grebnev <a href="mailto:andrey.grebnev@blandware.com"><andrey.grebnev@blandware.com></a>
|
||||||
|
* @version $Revision$ $Date$
|
||||||
|
*/
|
||||||
|
public class Enumerator implements Enumeration {
|
||||||
|
|
||||||
|
// ----------------------------------------------------------- Constructors
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>Iterator</code> over which the <code>Enumeration</code>
|
||||||
|
* represented by this class actually operates.
|
||||||
|
*/
|
||||||
|
private Iterator iterator = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an Enumeration over the values of the specified Collection.
|
||||||
|
*
|
||||||
|
* @param collection Collection whose values should be enumerated
|
||||||
|
*/
|
||||||
|
public Enumerator(Collection collection) {
|
||||||
|
this(collection.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an Enumeration over the values of the specified Collection.
|
||||||
|
*
|
||||||
|
* @param collection Collection whose values should be enumerated
|
||||||
|
* @param clone true to clone iterator
|
||||||
|
*/
|
||||||
|
public Enumerator(Collection collection, boolean clone) {
|
||||||
|
this(collection.iterator(), clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an Enumeration over the values returned by the
|
||||||
|
* specified Iterator.
|
||||||
|
*
|
||||||
|
* @param iterator Iterator to be wrapped
|
||||||
|
*/
|
||||||
|
public Enumerator(Iterator iterator) {
|
||||||
|
super();
|
||||||
|
this.iterator = iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an Enumeration over the values returned by the
|
||||||
|
* specified Iterator.
|
||||||
|
*
|
||||||
|
* @param iterator Iterator to be wrapped
|
||||||
|
* @param clone true to clone iterator
|
||||||
|
*/
|
||||||
|
public Enumerator(Iterator iterator, boolean clone) {
|
||||||
|
|
||||||
|
super();
|
||||||
|
if (!clone) {
|
||||||
|
this.iterator = iterator;
|
||||||
|
} else {
|
||||||
|
List list = new ArrayList();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
list.add(iterator.next());
|
||||||
|
}
|
||||||
|
this.iterator = list.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an Enumeration over the values of the specified Map.
|
||||||
|
*
|
||||||
|
* @param map Map whose values should be enumerated
|
||||||
|
*/
|
||||||
|
public Enumerator(Map map) {
|
||||||
|
this(map.values().iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an Enumeration over the values of the specified Map.
|
||||||
|
*
|
||||||
|
* @param map Map whose values should be enumerated
|
||||||
|
* @param clone true to clone iterator
|
||||||
|
*/
|
||||||
|
public Enumerator(Map map, boolean clone) {
|
||||||
|
this(map.values().iterator(), clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if this enumeration contains more elements.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if and only if this enumeration object
|
||||||
|
* contains at least one more element to provide, <code>false</code>
|
||||||
|
* otherwise
|
||||||
|
*/
|
||||||
|
public boolean hasMoreElements() {
|
||||||
|
return (iterator.hasNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next element of this enumeration if this enumeration
|
||||||
|
* has at least one more element to provide.
|
||||||
|
*
|
||||||
|
* @return the next element of this enumeration
|
||||||
|
*
|
||||||
|
* @exception NoSuchElementException if no more elements exist
|
||||||
|
*/
|
||||||
|
public Object nextElement() throws NoSuchElementException {
|
||||||
|
return (iterator.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,226 @@
|
||||||
|
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.sf.acegisecurity.wrapper.redirect;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Utility class to generate HTTP dates.</p>
|
||||||
|
* <p><a href="FastHttpDateFormat.java.html"><i>View Source</i></a></p>
|
||||||
|
* <p>This source code is taken from Tomcat Apache</p>
|
||||||
|
*
|
||||||
|
* @author Remy Maucherat
|
||||||
|
* @author Andrey Grebnev <a href="mailto:andrey.grebnev@blandware.com"><andrey.grebnev@blandware.com></a>
|
||||||
|
* @version $Revision$ $Date$
|
||||||
|
*/
|
||||||
|
public class FastHttpDateFormat {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current formatted date.
|
||||||
|
*/
|
||||||
|
protected static String currentDate = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instant on which the currentDate object was generated.
|
||||||
|
*/
|
||||||
|
protected static long currentDateGenerated = 0L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP date format.
|
||||||
|
*/
|
||||||
|
protected static final SimpleDateFormat format =
|
||||||
|
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formatter cache.
|
||||||
|
*/
|
||||||
|
protected static final HashMap formatCache = new HashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of SimpleDateFormat formats to use in <code>getDateHeader()</code>.
|
||||||
|
*/
|
||||||
|
protected static final SimpleDateFormat formats[] = {
|
||||||
|
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
|
||||||
|
new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
|
||||||
|
new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GMT timezone - all HTTP dates are on GMT
|
||||||
|
*/
|
||||||
|
protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parser cache.
|
||||||
|
*/
|
||||||
|
protected static final HashMap parseCache = new HashMap();
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
format.setTimeZone(gmtZone);
|
||||||
|
|
||||||
|
formats[0].setTimeZone(gmtZone);
|
||||||
|
formats[1].setTimeZone(gmtZone);
|
||||||
|
formats[2].setTimeZone(gmtZone);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a specified date to HTTP format. If local format is not
|
||||||
|
* <code>null</code>, it's used instead.
|
||||||
|
*
|
||||||
|
* @param value Date value to format
|
||||||
|
* @param threadLocalformat The format to use (or <code>null</code> -- then
|
||||||
|
* HTTP format will be used)
|
||||||
|
* @return Formatted date
|
||||||
|
*/
|
||||||
|
public static final String formatDate(long value,
|
||||||
|
DateFormat threadLocalformat) {
|
||||||
|
|
||||||
|
String cachedDate = null;
|
||||||
|
Long longValue = new Long(value);
|
||||||
|
try {
|
||||||
|
cachedDate = (String) formatCache.get(longValue);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
if (cachedDate != null)
|
||||||
|
return cachedDate;
|
||||||
|
|
||||||
|
String newDate = null;
|
||||||
|
Date dateValue = new Date(value);
|
||||||
|
if (threadLocalformat != null) {
|
||||||
|
newDate = threadLocalformat.format(dateValue);
|
||||||
|
synchronized (formatCache) {
|
||||||
|
updateCache(formatCache, longValue, newDate);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
synchronized (formatCache) {
|
||||||
|
newDate = format.format(dateValue);
|
||||||
|
updateCache(formatCache, longValue, newDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newDate;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current date in HTTP format.
|
||||||
|
*
|
||||||
|
* @return Current date in HTTP format
|
||||||
|
*/
|
||||||
|
public static final String getCurrentDate() {
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if ((now - currentDateGenerated) > 1000) {
|
||||||
|
synchronized (format) {
|
||||||
|
if ((now - currentDateGenerated) > 1000) {
|
||||||
|
currentDateGenerated = now;
|
||||||
|
currentDate = format.format(new Date(now));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return currentDate;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses date with given formatters.
|
||||||
|
*
|
||||||
|
* @param value The string to parse
|
||||||
|
* @param formats Array of formats to use
|
||||||
|
* @return Parsed date (or <code>null</code> if no formatter mached)
|
||||||
|
*/
|
||||||
|
private static final Long internalParseDate
|
||||||
|
(String value, DateFormat[] formats) {
|
||||||
|
Date date = null;
|
||||||
|
for (int i = 0; (date == null) && (i < formats.length); i++) {
|
||||||
|
try {
|
||||||
|
date = formats[i].parse(value);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (date == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Long(date.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to parse the given date as an HTTP date. If local format list is not
|
||||||
|
* <code>null</code>, it's used instead.
|
||||||
|
*
|
||||||
|
* @param value The string to parse
|
||||||
|
* @param threadLocalformats Array of formats to use for parsing.
|
||||||
|
* If <code>null</code>, HTTP formats are used.
|
||||||
|
* @return Parsed date (or -1 if error occured)
|
||||||
|
*/
|
||||||
|
public static final long parseDate(String value,
|
||||||
|
DateFormat[] threadLocalformats) {
|
||||||
|
|
||||||
|
Long cachedDate = null;
|
||||||
|
try {
|
||||||
|
cachedDate = (Long) parseCache.get(value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
if (cachedDate != null)
|
||||||
|
return cachedDate.longValue();
|
||||||
|
|
||||||
|
Long date = null;
|
||||||
|
if (threadLocalformats != null) {
|
||||||
|
date = internalParseDate(value, threadLocalformats);
|
||||||
|
synchronized (parseCache) {
|
||||||
|
updateCache(parseCache, value, date);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
synchronized (parseCache) {
|
||||||
|
date = internalParseDate(value, formats);
|
||||||
|
updateCache(parseCache, value, date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (date == null) {
|
||||||
|
return (-1L);
|
||||||
|
} else {
|
||||||
|
return date.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates cache.
|
||||||
|
*
|
||||||
|
* @param cache Cache to be updated
|
||||||
|
* @param key Key to be updated
|
||||||
|
* @param value New value
|
||||||
|
*/
|
||||||
|
private static final void updateCache(HashMap cache, Object key,
|
||||||
|
Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cache.size() > 1000) {
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
cache.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,352 @@
|
||||||
|
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.sf.acegisecurity.wrapper.redirect;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.http.Cookie;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter;
|
||||||
|
import net.sf.acegisecurity.wrapper.SecurityContextHolderAwareRequestWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Object that saves the critical information from a request so that
|
||||||
|
* HTTP (header and parameter)-based authentication can reproduce it
|
||||||
|
* once the user has been authenticated.
|
||||||
|
* <p>
|
||||||
|
* <b>IMPLEMENTATION NOTE</b> - It is assumed that this object is accessed
|
||||||
|
* only from the context of a single thread, so no synchronization around
|
||||||
|
* internal collection classes is performed.
|
||||||
|
* <p>
|
||||||
|
* Note that SavedHttpServletRequest doesn't save uploaded file binary data, although
|
||||||
|
* it does save request parameters so that a POST transaction can be faithfully
|
||||||
|
* duplicated. On one hand it is unfortunate to lose such type of data, but on
|
||||||
|
* the other hand we don't store it in session because the data can be very big
|
||||||
|
* and this solution can overload restricted resources.
|
||||||
|
* </p>
|
||||||
|
* <p>The original source code from Apache Tomcat<p>
|
||||||
|
*
|
||||||
|
* @see SecurityEnforcementFilter
|
||||||
|
* @see SecurityContextHolderAwareRequestWrapper
|
||||||
|
* @author Craig R. McClanahan
|
||||||
|
* @author Andrey Grebnev <a href="mailto:andrey.grebnev@blandware.com"><andrey.grebnev@blandware.com></a>
|
||||||
|
* @version $Revision$ $Date$
|
||||||
|
*/
|
||||||
|
public class SavedHttpServletRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method provides ability to create SavedHttpServletRequest from HttpServletRequest
|
||||||
|
* @param request request to be saved
|
||||||
|
* @return saved request resulting SavedHttpServletRequest
|
||||||
|
*/
|
||||||
|
public static SavedHttpServletRequest saveRequest(HttpServletRequest request) {
|
||||||
|
if (request.getRequestURI() == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Create and populate a SavedHttpServletRequest object for this request
|
||||||
|
SavedHttpServletRequest saved = new SavedHttpServletRequest();
|
||||||
|
Cookie cookies[] = request.getCookies();
|
||||||
|
if (cookies != null) {
|
||||||
|
for (int i = 0; i < cookies.length; i++)
|
||||||
|
saved.addCookie(cookies[i]);
|
||||||
|
}
|
||||||
|
Enumeration names = request.getHeaderNames();
|
||||||
|
while (names.hasMoreElements()) {
|
||||||
|
String name = (String) names.nextElement();
|
||||||
|
Enumeration values = request.getHeaders(name);
|
||||||
|
while (values.hasMoreElements()) {
|
||||||
|
String value = (String) values.nextElement();
|
||||||
|
saved.addHeader(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Enumeration locales = request.getLocales();
|
||||||
|
while (locales.hasMoreElements()) {
|
||||||
|
Locale locale = (Locale) locales.nextElement();
|
||||||
|
saved.addLocale(locale);
|
||||||
|
}
|
||||||
|
Map parameters = request.getParameterMap();
|
||||||
|
Iterator paramNames = parameters.keySet().iterator();
|
||||||
|
while (paramNames.hasNext()) {
|
||||||
|
String paramName = (String) paramNames.next();
|
||||||
|
String paramValues[] = (String[]) parameters.get(paramName);
|
||||||
|
saved.addParameter(paramName, paramValues);
|
||||||
|
}
|
||||||
|
saved.setMethod(request.getMethod());
|
||||||
|
saved.setQueryString(request.getQueryString());
|
||||||
|
saved.setRequestURI(request.getRequestURI());
|
||||||
|
// saved.setPathInfo(request.getPathInfo());
|
||||||
|
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of Cookies associated with this Request.
|
||||||
|
*/
|
||||||
|
private ArrayList cookies = new ArrayList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of Headers associated with this Request. Each key is a header
|
||||||
|
* name, while the value is a ArrayList containing one or more actual
|
||||||
|
* values for this header. The values are returned as an Iterator when
|
||||||
|
* you ask for them.
|
||||||
|
*/
|
||||||
|
private HashMap headers = new HashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of Locales associated with this Request.
|
||||||
|
*/
|
||||||
|
private ArrayList locales = new ArrayList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The request method used on this Request.
|
||||||
|
*/
|
||||||
|
private String method = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of request parameters associated with this Request. Each
|
||||||
|
* entry is keyed by the parameter name, pointing at a String array of
|
||||||
|
* the corresponding values.
|
||||||
|
*/
|
||||||
|
private HashMap parameters = new HashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The request pathInfo associated with this Request.
|
||||||
|
*/
|
||||||
|
private String pathInfo = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The query string associated with this Request.
|
||||||
|
*/
|
||||||
|
private String queryString = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The request URI associated with this Request.
|
||||||
|
*/
|
||||||
|
private String requestURI = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds cookie to list of cookies
|
||||||
|
*
|
||||||
|
* @param cookie cookie to add
|
||||||
|
*/
|
||||||
|
public void addCookie(Cookie cookie) {
|
||||||
|
cookies.add(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds header
|
||||||
|
*
|
||||||
|
* @param name header name
|
||||||
|
* @param value header value
|
||||||
|
*/
|
||||||
|
public void addHeader(String name, String value) {
|
||||||
|
ArrayList values = (ArrayList) headers.get(name);
|
||||||
|
if (values == null) {
|
||||||
|
values = new ArrayList();
|
||||||
|
headers.put(name, values);
|
||||||
|
}
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds locale
|
||||||
|
*
|
||||||
|
* @param locale locale to add
|
||||||
|
*/
|
||||||
|
public void addLocale(Locale locale) {
|
||||||
|
locales.add(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds parameter
|
||||||
|
*
|
||||||
|
* @param name parameter name
|
||||||
|
* @param values parameter values
|
||||||
|
*/
|
||||||
|
public void addParameter(String name, String values[]) {
|
||||||
|
parameters.put(name, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns list of cookies
|
||||||
|
*
|
||||||
|
* @return list of cookies
|
||||||
|
*/
|
||||||
|
public List getCookies() {
|
||||||
|
return cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns iterator over header names
|
||||||
|
*
|
||||||
|
* @return iterator over header names
|
||||||
|
*/
|
||||||
|
public Iterator getHeaderNames() {
|
||||||
|
return (headers.keySet().iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns iterator over header values
|
||||||
|
*
|
||||||
|
* @param name header name
|
||||||
|
* @return iterator over header values
|
||||||
|
*/
|
||||||
|
public Iterator getHeaderValues(String name) {
|
||||||
|
ArrayList values = (ArrayList) headers.get(name);
|
||||||
|
if (values == null)
|
||||||
|
return ((new ArrayList()).iterator());
|
||||||
|
else
|
||||||
|
return (values.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns iterator over locales
|
||||||
|
*
|
||||||
|
* @return iterator over locales
|
||||||
|
*/
|
||||||
|
public Iterator getLocales() {
|
||||||
|
return (locales.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns request method
|
||||||
|
*
|
||||||
|
* @return request method
|
||||||
|
*/
|
||||||
|
public String getMethod() {
|
||||||
|
return (this.method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns parameters
|
||||||
|
*
|
||||||
|
* @return parameters map
|
||||||
|
*/
|
||||||
|
public Map getParameterMap() {
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns iterator over parameter names
|
||||||
|
*
|
||||||
|
* @return iterator over parameter names
|
||||||
|
*/
|
||||||
|
public Iterator getParameterNames() {
|
||||||
|
return (parameters.keySet().iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns parameter values
|
||||||
|
*
|
||||||
|
* @param name parameter name
|
||||||
|
* @return parameter values
|
||||||
|
*/
|
||||||
|
public String[] getParameterValues(String name) {
|
||||||
|
return ((String[]) parameters.get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns path info
|
||||||
|
*
|
||||||
|
* @return path info
|
||||||
|
*/
|
||||||
|
public String getPathInfo() {
|
||||||
|
return pathInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns query string
|
||||||
|
*
|
||||||
|
* @return query string
|
||||||
|
*/
|
||||||
|
public String getQueryString() {
|
||||||
|
return (this.queryString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns request URI
|
||||||
|
*
|
||||||
|
* @return request URI
|
||||||
|
*/
|
||||||
|
public String getRequestURI() {
|
||||||
|
return (this.requestURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets uri with path info and query string
|
||||||
|
*
|
||||||
|
* @return uri with path info and query string
|
||||||
|
*/
|
||||||
|
public String getRequestURL() {
|
||||||
|
if (getRequestURI() == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
StringBuffer sb = new StringBuffer(getRequestURI());
|
||||||
|
// if (getPathInfo() != null) {
|
||||||
|
// sb.append(getPathInfo());
|
||||||
|
// }
|
||||||
|
if (getQueryString() != null) {
|
||||||
|
sb.append('?');
|
||||||
|
sb.append(getQueryString());
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets request method
|
||||||
|
*
|
||||||
|
* @param method request method to set
|
||||||
|
*/
|
||||||
|
public void setMethod(String method) {
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets path info
|
||||||
|
*
|
||||||
|
* @param pathInfo path info to set
|
||||||
|
*/
|
||||||
|
public void setPathInfo(String pathInfo) {
|
||||||
|
this.pathInfo = pathInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets query string
|
||||||
|
*
|
||||||
|
* @param queryString query string to set
|
||||||
|
*/
|
||||||
|
public void setQueryString(String queryString) {
|
||||||
|
this.queryString = queryString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets request URI
|
||||||
|
*
|
||||||
|
* @param requestURI request URI to set
|
||||||
|
*/
|
||||||
|
public void setRequestURI(String requestURI) {
|
||||||
|
this.requestURI = requestURI;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Redirection helper code for
|
||||||
|
<code>SecurityContextHolderAwareRequestWrapper</code>
|
||||||
|
and
|
||||||
|
<code>SecurityEnforcementFilter</code>.
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue