You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by bu...@apache.org on 2002/02/06 18:21:42 UTC
DO NOT REPLY [Bug 6279] New: -
Resubmit to j_security_check mistakenly fetches a page of that name
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=6279>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND
INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=6279
Resubmit to j_security_check mistakenly fetches a page of that name
Summary: Resubmit to j_security_check mistakenly fetches a page
of that name
Product: Tomcat 4
Version: 4.0.1 Final
Platform: All
OS/Version: All
Status: NEW
Severity: Normal
Priority: Other
Component: HTTP/1.1 Connector
AssignedTo: tomcat-dev@jakarta.apache.org
ReportedBy: Brian.Ewins@btinternet.com
This ought to be easy to reproduce...if you go to a page secured by form-based
authentication in a webapp under catalina, you are displayed the login form.
Log in, you see the page you asked for. Now click 'back' in the browser. You
get the login form again. Resubmit the form.
You will end up at a tomcat 404 error page, explaining that the
resource /some/path/to/j_security_check does not exist.
Its not that unusual a thing for users to do, it seems; three out of four
testers spotted it in our site without being told to look for it.
The problem appears to be in
org.apache.catalina.authenticator.FormAuthenticator.java . This /does/ get
invoked if the request is for j_security_check, by this code in
AuthenticatorBase:
if (requestURI.startsWith(contextPath) &&
requestURI.endsWith(Constants.FORM_ACTION)) {
if (!authenticate(hrequest, hresponse, config)) {
...etc
However as soon as the code enters FormAuthenticator.authenticate it checks for
a non-null principal, and if it finds one, it returns immediately. Because
there is no check here that the uri requested matches j_security_check, the
user is taken directly to j_security_check, instead of reauthenticating or
sending the user to the URL saved in the session.
The spec is silent on this situation. I would guess that if someone resubmits
they want to re-authenticate, potentially as someone else. The code could be
fixed at the test in AuthenticatorBase, but this may have side effects if
j_security_check is requested when using other forms of authenticator. It seems
best to patch FormAuthenticator.java, like so (changes marked 'BE'):
public boolean authenticate(HttpRequest request,
HttpResponse response,
LoginConfig config)
throws IOException {
// References to objects we will need later
HttpServletRequest hreq =
(HttpServletRequest) request.getRequest();
HttpServletResponse hres =
(HttpServletResponse) response.getResponse();
Session session = null;
// BE: moved three declarations and their comments to top
// Acquire references to objects we will need to evaluate
String contextPath = hreq.getContextPath();
String requestURI = hreq.getRequestURI();
// Is this the action request from the login page?
boolean loginAction =
requestURI.startsWith(contextPath) &&
requestURI.endsWith(Constants.FORM_ACTION);
// Have we already authenticated someone?
Principal principal = hreq.getUserPrincipal();
// BE: added check for loginAction
if (principal != null && !loginAction) {
if (debug >= 1)
log("Already authenticated '" +
principal.getName() + "'");
String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
if (ssoId != null)
associate(ssoId, getSession(request, true));
return (true);
}
// Have we authenticated this user before but have caching disabled?
// BE: added check for loginAction - would have had same problem
if (!cache && !loginAction) {
session = getSession(request, true);
if (debug >= 1)
log("Checking for reauthenticate in session " + session);
String username =
(String) session.getNote(Constants.SESS_USERNAME_NOTE);
String password =
(String) session.getNote(Constants.SESS_PASSWORD_NOTE);
if ((username != null) && (password != null)) {
if (debug >= 1)
log("Reauthenticating username '" + username + "'");
principal =
context.getRealm().authenticate(username, password);
if (principal != null) {
session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
register(request, response, principal,
Constants.FORM_METHOD,
username, password);
return (true);
}
if (debug >= 1)
log("Reauthentication failed, proceed normally");
}
}
// Is this the re-submit of the original request URI after successful
// authentication? If so, forward the *original* request instead.
// BE: will still have a problem here if someone directly requested the
// j_security_check page! Should really send an error response for
// that case.
if (matchRequest(request)) {
session = getSession(request, true);
if (debug >= 1)
log("Restore request from session '" + session.getId() + "'");
principal = (Principal)
session.getNote(Constants.FORM_PRINCIPAL_NOTE);
register(request, response, principal, Constants.FORM_METHOD,
(String) session.getNote(Constants.SESS_USERNAME_NOTE),
(String) session.getNote(Constants.SESS_PASSWORD_NOTE));
String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
if (ssoId != null)
associate(ssoId, session);
if (restoreRequest(request, session)) {
if (debug >= 1)
log("Proceed to restored request");
return (true);
} else {
if (debug >= 1)
log("Restore of original request failed");
hres.sendError(HttpServletResponse.SC_BAD_REQUEST);
return (false);
}
}
// Acquire references to objects we will need to evaluate
// BE: moved two declarations to start of method
response.setContext(request.getContext());
// Is this a request for the login page itself? Test here to avoid
// displaying it twice (from the user's perspective) -- once because
// of the "save and redirect" and once because of the "restore and
// redirect" performed below.
String loginURI = contextPath + config.getLoginPage();
if (requestURI.equals(loginURI)) {
if (debug >= 1)
log("Requesting login page normally");
return (true); // Display the login page in the usual manner
}
// Is this a request for the error page itself? Test here to avoid
// an endless loop (back to the login page) if the error page is
// within the protected area of our security constraint
String errorURI = contextPath + config.getErrorPage();
if (requestURI.equals(errorURI)) {
if (debug >= 1)
log("Requesting error page normally");
return (true); // Display the error page in the usual manner
}
// BE - declaration of loginAction moved to start of method
// Is this the action request from the login page?
// No -- Save this request and redirect to the form login page
if (!loginAction) {
session = getSession(request, true);
if (debug >= 1)
log("Save request in session '" + session.getId() + "'");
saveRequest(request, session);
if (debug >= 1)
log("Redirect to login page '" + loginURI + "'");
hres.sendRedirect(hres.encodeRedirectURL(loginURI));
return (false);
}
// Yes -- Validate the specified credentials and redirect
// to the error page if they are not correct
Realm realm = context.getRealm();
String username = hreq.getParameter(Constants.FORM_USERNAME);
String password = hreq.getParameter(Constants.FORM_PASSWORD);
if (debug >= 1)
log("Authenticating username '" + username + "'");
principal = realm.authenticate(username, password);
if (principal == null) {
if (debug >= 1)
log("Redirect to error page '" + errorURI + "'");
hres.sendRedirect(hres.encodeRedirectURL(errorURI));
return (false);
}
// Save the authenticated Principal in our session
if (debug >= 1)
log("Authentication of '" + username + "' was successful");
if (session == null)
session = getSession(request, true);
session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
// If we are not caching, save the username and password as well
if (!cache) {
session.setNote(Constants.SESS_USERNAME_NOTE, username);
session.setNote(Constants.SESS_PASSWORD_NOTE, password);
}
// Redirect the user to the original request URI (which will cause
// the original request to be restored)
requestURI = savedRequestURL(session);
if (debug >= 1)
log("Redirecting to original '" + requestURI + "'");
if (requestURI == null)
hres.sendError(HttpServletResponse.SC_BAD_REQUEST,
sm.getString("authenticator.formlogin"));
else
hres.sendRedirect(hres.encodeRedirectURL(requestURI));
return (false);
}
Looks like this could be tidied up considerably to decrease the number of
loginAction checks, but hopefully the changes above will resolve the problem.
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>