If I use BASIC authentication, tomcat obviously tries to authenticate an initial request against the security provider although the request does not include the "Authorization: ..." header yet! I have not tracked what credentials are used but the assumption in the tomcat implementation seems to be that trying authorization with the used "default credentials" should fail anyway, causing tomcat to then send the 401 reply and the browser to display the login dialog. Although I have to admit that I could not find something specific in the specifications, I think this behaviour is a bug. Tomcat should query the security provider only if it has received the "Authorization: ..." header as part of the request. Any request of a resource secured with BASIC authentication that lacks this header should result in an immediate 401 response, i.e. without consulting the security provider. Why is this important? Well, especially in a J2EE environment a security realm may support something like an "unauthenticated identity" used for anonymous access of certain resources (but not the servlet in question). The current behaviour of tomcat has the effect that there is an authorization request without credentials and the user is (without ever being prompted by the browser) identified as the anonymous user. As tomcat thinks identification has been successfully performed, it does not repond with a 401 but rather continues processing with the unauthenticated identity. This identity may (usually does) lack a lot of the rights that an authenticated user has and thus the user receives a 403.
The closest thing I could find in the spec to what you describe is in J2EE.3.4.3 Unauthenticated Users. This makes clear that the anonymous user is unathenticated and that the container is responsible for providing a suitable principal for unauthenitcated users to the EJB container. Authentication is only required for protected resources and Tomcat will only prompt for authentication when accessing a protected resource. Tomcat is consistent with the required behaviour.
> Authentication is only required for protected resources and Tomcat will only > prompt for authentication when accessing a protected resource. This is wrong. The whole point is that Tomcat DOES NOT PROMPT when basic authentication is used. If the security module allows an unauthenticated user, you never get the opportunity to authenticate as someone different, because Tomcat never sends 401 to the browser. Tomcat finds that the resource I'm trying to access is protected. This is OK. But instead of sending a 401 and give me the opportunity to provide credentials, it obviously immediately tries to "authenticate as unauthenticated user". If this is successful, it simply continues with this identity and I never get a prompt. Acing like this, Tomcat is not consistent in its behaviour. Try form based authentication instead. If you use form based authentication, Tomcat ALWAYS shows the login form first, even if the security realm supports an unauthenticated identity. If form based authentication had been implemented just as basic authentication, Tomcat would find that the resource is protected, try to authenticate, find that the "unautheticated identity" works and continue with this identity, never showing the login form. But it does! The point is that basic authentication and form based authentication behave differently when the security realm supports an unauthenticated identity. Using form based authentication, you are prompted for credentials; using basic authentication, you are not prompted. You cannot derive from the specs which behaviour is correct, I agree with this. However, Tomcat should consistently stick to one of those possibilities and should not act differently depending on the authentication method chosen.
I have done some testing with the latest code from CVS but the behaviour should be the same with 4.1.24 The key is how your realm authenticates when username=null and when username="" username=null when there are no authentication headers username="" when there are headers but the user just hit enter on the BASIC auth dialog I have tested this with the memory realm with entries in tomcat-users.xml of the form: <user username="" password="" roles="bug22617"/> <user username="tomcat" password="tomcat" roles="tomcat"/> and web.xml entries that look like: <security-constraint> <display-name>Bug 22617</display-name> <web-resource-collection> <web-resource-name>Bug 22617</web-resource-name> <url-pattern>/bug22617/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>bug22617</role-name> <role-name>tomcat</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> </login-config> With this configuration I always get prompted for a user name and password and just pressing enter or using tomcat/tomact allows me to see the page. Based on this, I am pretty sure you need to change your Realm implementation so that username=null always fails authentication. Given that Realm is an internal Tomcat interface, I don't see this as being an unreasonable requirement to be placed on custom Realm implementations. I agree that the behaviour is inconsistent if the Realm treats username=null and username="" as equivalent. However, I believe such behaviour in a realm is not correct. I'll leave this open for now until you respond, but I am minded to close this as invalid.
I think you are bluring the distinction between a user not being identified (yet) and thus being "null" and the user with name "". I admit that the latter is a very short username, but -- as you state -- this is what the browser-user has entered by simply hitting enter. In my opinion, user "" is no longer anonymous, it is simply a user with a very short name. Of course, a Realm implementation may take this as a shortcut for "anonymous" or "nobody", and assign the "unauthenticated identity", but it may as well require a password for this username. I still consider it an error that Tomcat calls the Realm implementation at all if authentication is BASIC and it has not received any authentication headers yet. It should simply have the browser prompt the user for credentials, just like form based authentication ALWAYS displays the form (and does not call the Realm implementation first with username being "null"). Of course, the Realm interface is an internal interface. But the point is that Tomcat invokes this interface differently depending on the authentication method used! The practical problem is that I actually do not supply the realm implementation, JBoss does. I simply supply a JAAS login module. And in a J2EE/JBoss context, I have to accept a user being "null" as the anonymous user, because this is what my J2EE clients use as credentials when trying to access anonymously (if I was to follow your line, a client that wanted to act with the unauthenticated identity would have to include the necesary code to set the username to "" -- I don't think this is reasonable). Now don't say "well this is a JBoss problem"; I strongly doubt that e.g. Geronimo uses username "" instead of user being "null" to represent an anonymous client. I still think a fix would be quite simple: if ((authentication == BASIC) AND (no authentication headers)) { "send 401 to browser" }. This would make the behaviour consistent with form based login (and Jetty and WebLogicServer, btw. -- not being able to derive the correct behaviour from the specifications, this may be a point). As a user, I can still hit the return key and if the Realm implementation allows anonymous access, it can assign the "unauthenticated identity" if username is "" and password is "" (as you have proposed the Realm implementation should).
Got it. As soon as I read your last post it all made sense. Your are right, this is a bug and the fix is simple. I have commited a fix for this to TC4.1.x and TC5.5.x