405435 Implement servlet3.1 section 13.6.3 for 303 redirects for Form auth
This commit is contained in:
parent
fb43fd4c9e
commit
348cbc2173
|
@ -52,9 +52,25 @@ public interface Authenticator
|
|||
* @return The name of the authentication method
|
||||
*/
|
||||
String getAuthMethod();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Called prior to validateRequest. The authenticator can
|
||||
* manipulate the request to update it with information that
|
||||
* can be inspected prior to validateRequest being called.
|
||||
* The primary purpose of this method is to satisfy the Servlet
|
||||
* Spec 3.1 section 13.6.3 on handling Form authentication
|
||||
* where the http method of the original request causing authentication
|
||||
* is not the same as the http method resulting from the redirect
|
||||
* after authentication.
|
||||
* @param request
|
||||
*/
|
||||
void prepareRequest(ServletRequest request);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Validate a response
|
||||
/** Validate a request
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
* @param mandatory True if authentication is mandatory.
|
||||
|
|
|
@ -462,6 +462,10 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
|||
|
||||
if (checkSecurity(baseRequest))
|
||||
{
|
||||
//See Servlet Spec 3.1 sec 13.6.3
|
||||
if (authenticator != null)
|
||||
authenticator.prepareRequest(baseRequest);
|
||||
|
||||
RoleInfo roleInfo = prepareConstraintInfo(pathInContext, baseRequest);
|
||||
|
||||
// Check data constraints
|
||||
|
|
|
@ -36,6 +36,7 @@ import javax.servlet.http.HttpSession;
|
|||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.security.ServerAuthException;
|
||||
import org.eclipse.jetty.security.UserAuthentication;
|
||||
|
@ -43,6 +44,7 @@ import org.eclipse.jetty.server.Authentication;
|
|||
import org.eclipse.jetty.server.Authentication.User;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -75,6 +77,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
public final static String __FORM_DISPATCH="org.eclipse.jetty.security.dispatch";
|
||||
public final static String __J_URI = "org.eclipse.jetty.security.form_URI";
|
||||
public final static String __J_POST = "org.eclipse.jetty.security.form_POST";
|
||||
public final static String __J_METHOD = "org.eclipse.jetty.security.form_METHOD";
|
||||
public final static String __J_SECURITY_CHECK = "/j_security_check";
|
||||
public final static String __J_USERNAME = "j_username";
|
||||
public final static String __J_PASSWORD = "j_password";
|
||||
|
@ -198,6 +201,45 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void prepareRequest(ServletRequest request)
|
||||
{
|
||||
//if this is a request resulting from a redirect after auth is complete
|
||||
//(ie its from a redirect to the original request uri) then due to
|
||||
//browser handling of 302 redirects, the method may not be the same as
|
||||
//that of the original request. Replace the method and original post
|
||||
//params (if it was a post).
|
||||
//
|
||||
//See Servlet Spec 3.1 sec 13.6.3
|
||||
HttpServletRequest httpRequest = (HttpServletRequest)request;
|
||||
HttpSession session = httpRequest.getSession(false);
|
||||
if (session == null || session.getAttribute(SessionAuthentication.__J_AUTHENTICATED) == null)
|
||||
return; //not authenticated yet
|
||||
|
||||
String juri = (String)session.getAttribute(__J_URI);
|
||||
if (juri == null || juri.length() == 0)
|
||||
return; //no original uri saved
|
||||
|
||||
String method = (String)session.getAttribute(__J_METHOD);
|
||||
if (method == null || method.length() == 0)
|
||||
return; //didn't save original request method
|
||||
|
||||
StringBuffer buf = httpRequest.getRequestURL();
|
||||
if (httpRequest.getQueryString() != null)
|
||||
buf.append("?").append(httpRequest.getQueryString());
|
||||
|
||||
if (!juri.equals(buf.toString()))
|
||||
return; //this request is not for the same url as the original
|
||||
|
||||
//restore the original request's method on this request
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Restoring original method {} for {} with method {}", method, juri,httpRequest.getMethod());
|
||||
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
HttpMethod m = HttpMethod.fromString(method);
|
||||
base_request.setMethod(m,m.asString());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
|
@ -249,7 +291,10 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
LOG.debug("authenticated {}->{}",form_auth,nuri);
|
||||
|
||||
response.setContentLength(0);
|
||||
response.sendRedirect(response.encodeRedirectURL(nuri));
|
||||
Response base_response = HttpChannel.getCurrentHttpChannel().getResponse();
|
||||
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
int redirectCode = (base_request.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER);
|
||||
base_response.sendRedirect(redirectCode, response.encodeRedirectURL(nuri));
|
||||
return form_auth;
|
||||
}
|
||||
|
||||
|
@ -273,7 +318,10 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
else
|
||||
{
|
||||
LOG.debug("auth failed {}->{}",username,_formErrorPage);
|
||||
response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),_formErrorPage)));
|
||||
Response base_response = HttpChannel.getCurrentHttpChannel().getResponse();
|
||||
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
int redirectCode = (base_request.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER);
|
||||
base_response.sendRedirect(redirectCode, response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),_formErrorPage)));
|
||||
}
|
||||
|
||||
return Authentication.SEND_FAILURE;
|
||||
|
@ -298,28 +346,26 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
String j_uri=(String)session.getAttribute(__J_URI);
|
||||
if (j_uri!=null)
|
||||
{
|
||||
//check if the request is for the same url as the original and restore
|
||||
//params if it was a post
|
||||
LOG.debug("auth retry {}->{}",authentication,j_uri);
|
||||
MultiMap<String> j_post = (MultiMap<String>)session.getAttribute(__J_POST);
|
||||
if (j_post!=null)
|
||||
StringBuffer buf = request.getRequestURL();
|
||||
if (request.getQueryString() != null)
|
||||
buf.append("?").append(request.getQueryString());
|
||||
|
||||
if (j_uri.equals(buf.toString()))
|
||||
{
|
||||
LOG.debug("auth rePOST {}->{}",authentication,j_uri);
|
||||
StringBuffer buf = request.getRequestURL();
|
||||
if (request.getQueryString() != null)
|
||||
buf.append("?").append(request.getQueryString());
|
||||
|
||||
if (j_uri.equals(buf.toString()))
|
||||
MultiMap<String> j_post = (MultiMap<String>)session.getAttribute(__J_POST);
|
||||
if (j_post!=null)
|
||||
{
|
||||
// This is a retry of an original POST request
|
||||
// so restore method and parameters
|
||||
|
||||
session.removeAttribute(__J_POST);
|
||||
LOG.debug("auth rePOST {}->{}",authentication,j_uri);
|
||||
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
base_request.setMethod(HttpMethod.POST,HttpMethod.POST.asString());
|
||||
base_request.setParameters(j_post);
|
||||
}
|
||||
}
|
||||
else
|
||||
session.removeAttribute(__J_URI);
|
||||
session.removeAttribute(__J_METHOD);
|
||||
session.removeAttribute(__J_POST);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.debug("auth {}",authentication);
|
||||
|
@ -344,6 +390,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
if (request.getQueryString() != null)
|
||||
buf.append("?").append(request.getQueryString());
|
||||
session.setAttribute(__J_URI, buf.toString());
|
||||
session.setAttribute(__J_METHOD, request.getMethod());
|
||||
|
||||
if (MimeTypes.Type.FORM_ENCODED.is(req.getContentType()) && HttpMethod.POST.is(request.getMethod()))
|
||||
{
|
||||
|
@ -366,7 +413,10 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
else
|
||||
{
|
||||
LOG.debug("challenge {}->{}",session.getId(),_formLoginPage);
|
||||
response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),_formLoginPage)));
|
||||
Response base_response = HttpChannel.getCurrentHttpChannel().getResponse();
|
||||
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
int redirectCode = (base_request.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER);
|
||||
base_response.sendRedirect(redirectCode, response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),_formLoginPage)));
|
||||
}
|
||||
return Authentication.SEND_CONTINUE;
|
||||
}
|
||||
|
|
|
@ -40,11 +40,20 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
protected LoginService _loginService;
|
||||
protected IdentityService _identityService;
|
||||
private boolean _renewSession;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected LoginAuthenticator()
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void prepareRequest(ServletRequest request)
|
||||
{
|
||||
//empty implementation as the default
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public UserIdentity login(String username, Object password, ServletRequest request)
|
||||
|
@ -58,7 +67,7 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void setConfiguration(AuthConfiguration configuration)
|
||||
{
|
||||
|
@ -70,12 +79,16 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
throw new IllegalStateException("No IdentityService for "+this+" in "+configuration);
|
||||
_renewSession=configuration.isSessionRenewedOnAuthentication();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public LoginService getLoginService()
|
||||
{
|
||||
return _loginService;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Change the session id.
|
||||
* The session is changed to a new instance with a new ID if and only if:<ul>
|
||||
* <li>A session exists.
|
||||
|
|
|
@ -686,6 +686,7 @@ public class ConstraintTest
|
|||
"Content-Length: 31\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=wrong\r\n");
|
||||
|
||||
assertThat(response,containsString("Location"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
|
|
|
@ -428,10 +428,18 @@ public class Response implements HttpServletResponse
|
|||
_channel.commitResponse(HttpGenerator.PROGRESS_102_INFO, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRedirect(String location) throws IOException
|
||||
|
||||
/**
|
||||
* Sends a response with one of the 300 series redirection codes.
|
||||
* @param code
|
||||
* @param location
|
||||
* @throws IOException
|
||||
*/
|
||||
public void sendRedirect(int code, String location) throws IOException
|
||||
{
|
||||
if ((code < HttpServletResponse.SC_MULTIPLE_CHOICES) || (code >= HttpServletResponse.SC_BAD_REQUEST))
|
||||
throw new IllegalArgumentException("Not a 3xx redirect code");
|
||||
|
||||
if (isIncluding())
|
||||
return;
|
||||
|
||||
|
@ -497,10 +505,16 @@ public class Response implements HttpServletResponse
|
|||
|
||||
resetBuffer();
|
||||
setHeader(HttpHeader.LOCATION, location);
|
||||
setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
|
||||
setStatus(code);
|
||||
complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRedirect(String location) throws IOException
|
||||
{
|
||||
sendRedirect(HttpServletResponse.SC_MOVED_TEMPORARILY, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDateHeader(String name, long date)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue