First problem, I didn't have the right logging enabled; I hadn't noticed that I didn't see any of the log messages from BasicAuthenticator.java.
Second problem, with logging cranked up appropriately, is that BasicAuthenticator gets called before my code.
Which leads to my next question: how can I get called before BasicAuthenticator?
I had the Valve installed as the first item in the Engine; when it's there it apparently gets called after BasicAuthenticator. I tried moving my valve up a level into the Service, but my code didn't seem to get called at all when I installed the valve there.
Let me ask a related question: If I have a valve that's setting the principal and authType, do I need to set a Realm in server.xml, and if so, what should I set it to? Do I need to write a Realm that somehow talks to my Valve (since the request info isn't available in Tomcat 4)? This is, I think, the piece of the puzzle that I don't completely understand.
Scott
At 5:03 PM -0400 6/11/03, Tim Funk wrote:
I took a little longer look. All "looks" ok to me. Turn up debugging. Are you sure that your valve is being executed before the BasicAuthenticator valve?
-Tim
Scott Kelley wrote:SingleSignOn has much the same code as BasicAuthenticator:
in org.apache.catalina.authenticator.SingleSignOn.java:
// Look up the cached Principal associated with this cookie value if (debug >= 1) log(" Checking for cached principal for " + cookie.getValue()); SingleSignOnEntry entry = lookup(cookie.getValue()); if (entry != null) { if (debug >= 1) log(" Found cached principal '" + entry.principal.getName() + "' with auth type '" + entry.authType + "'"); request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue()); ((HttpRequest) request).setAuthType(entry.authType); ((HttpRequest) request).setUserPrincipal(entry.principal); } else { if (debug >= 1) log(" No cached principal found, erasing SSO cookie"); cookie.setMaxAge(0); hres.addCookie(cookie); }
// Invoke the next Valve in our pipeline context.invokeNext(request, response);
The only piece of that I'm not doing is the setNote() part; I *think* that's only used for the form-based login stuff, but I'm not entirely sure-- that's probably the part of the puzzle I still don't understand. The basic authenicator doesn't seem to use it.
Scott
At 3:10 PM -0400 6/11/03, Tim Funk wrote:
I don't have time to see whats wrong, but check the SingleSignOnValve as a reference to compare your code.
-Tim
Scott Kelley wrote:
We've had an Apache/Tomcat configuration deployed for a couple years now. Authentication is handled by a custom Apache plugin written in C. Everything works great and has been quite reliable.
Now we would like to move to a standalone Tomcat configuration and have been investigating writing a Valve/Authenticator to replace our existing Apache plugin.
I've written a prototype Valve and it does almost everything we need. This gives us the ability to require a server-wide login independent of how the individual servlet contexts are configured. This ends up being Tomcat-specific, but we're ok with that.
The only problem with the current prototype is that if a user hits a servlet or JSP in a Context that's configured for basic authentication, they still get the browser-generated basic login dialog, even after being logged in with our Valve.
In my code, I check for a particular cookie, and if I find it, I set the user principal in the request to the appropriate user, something like this:
// Has connection already been authenticated // (i.e. do we have the login cookie?) Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);
// If the request has the login cookie, let it pass through
if (lcookie!=null) {
log("Found login cookie, validating");
if (validLoginCookie(lcookie,hreq)) {
log("cookie is valid, allowing request");
// See AuthenticatorBase.invoke(), which also sets authType and userPrincipal
// See SignleSignOn.invoke(), which also set authType and userPrincipal
hrequest.getRequest().setUserPrincipal(new TempPrincipal("bob_temp_user"));
hrequest.getRequest().setAuthType("BASIC");
context.invokeNext(request,response);
} else {
log("cookie not valid, going to error page");
hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
}
return;
}
I had thought that this would work, because later in the pipeline the request hits BasicAuthenticator, which does this:
public boolean authenticate(HttpRequest request, HttpResponse response, LoginConfig config) throws IOException {
// Have we already authenticated someone? Principal principal = ((HttpServletRequest) request.getRequest()).getUserPrincipal(); if (principal != null) { if (debug >= 1) log("Already authenticated '" + principal.getName() + "'"); return (true); }
And since I've set the principal to something besides null, I had assumed that the basic authentication would just be skipped. Which is not the behavior that I'm seeing. Instead, I end up asking the user to log in twice: once for my custom Valve (which is a web form/redirect thing), and a second time when they hit a servlet in a context with basic authentication (which causes the browser to put up the basic authentication dialog).
So, what am I missing?
Thanks,
Scott
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
