public boolean authenticate(HttpRequest request,
HttpResponse response,
LoginConfig config) throws IOException {
HttpServletRequest hreq =
(HttpServletRequest) request.getRequest();
// Have we already authenticated someone?
// Note: SingleSignOn does not call setUserPrincipal(),
// so whoever did it would have to be some custom valve
// in the pipeline
Principal principal = hreq.getUserPrincipal();
String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
if (principal != null)
{
if (debug >= 1)
log("Found principal '" + principal.getName() + "'");
// Associate the session with any existing SSO session
if (ssoId != null)
associate(ssoId, getSession(request, true));
return true;
}
// Is there an SSO session against which we can try to reauthenticate?
if (ssoId != null)
{
if (debug >= 1)
log("SSO Id set");
// Try to reauthenticate using data cached by SSO. If this fails,
// either the original SSO logon was of DIGEST or SSL (which
// we can't reauthenticate ourselves because there is no
// cached username and password), or the realm denied
// the user's reauthentication for some reason.
// In either case we have to prompt the user for a logon
if (reauthenticateFromSSO(ssoId, request))
return true;
}
// References to objects we will need later
HttpServletResponse hres =
(HttpServletResponse) response.getResponse();
Session session = null;
// Have we authenticated this user before but have caching disabled?
if (!cache)
{
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.
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));
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
String contextPath = hreq.getContextPath();
String requestURI = request.getDecodedRequestURI();
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
}
// Is this the action request from the login page?
boolean loginAction =
requestURI.startsWith(contextPath) &&
requestURI.endsWith(Constants.FORM_ACTION);
// 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);
}
Authenticate the user making this request, based on the specified
login configuration. Return true if any specified
constraint has been satisfied, or false if we have
created a response challenge already.
Differs from the standard Tomcat version in if no Principal
has already been authenticated to the request, method still checks
if SingleSignOn has set an SSO_ID note on the request.
SingleSignOn may do this if the single sign-on session
was created by an application using CERT or DIGEST authentication.
If it has, the note is removed so that when this authenticator registers
its authentication, a new single sign-on session will be created. |