Hi,

I want to implement discretionary access control in an app running in Tomcat - i.e. access controls on URLs served by Tomcat can be changed by users. I expect to have a 1M resources each with its own ACL. Some resources have 'public' access. No authentication should be required to access them. Access to some resources is constrained and does require authentication. The same resource may be access controlled one minute and public the next. The URL of a resource may not change when its ACL changes.

I have been approaching this by trying to use the built in Tomcat authentication and creating my own authorization filter. The problem I'm hitting is that getRemoteUser is returning null. I believe the reason it is returning null is that I have no <auth-constraint> element in my security constraint:

<security-constraint>
<display-name>Authenticate</display-name>
<web-resource-collection>
<web-resource-name>resources</web-resource-name>
<description></description>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>HEAD</http-method>
<http-method>PUT</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
</security-constraint>

Despite the fact that I have arranged for the incoming request to have an Authorization header (I send my own 401 responses), Tomcat does not process it unless the there is an <auth-constraint> that applies to the requested resource. This is consistent with what the servlet spec says:

[[An authorization constraint establishes a requirement for authentication ...]]

I want to have no authorization constraint because some resources have public access and no authentication is required for access to those resources.

I have tried using getRequestDispatcher(...).forward(...) to forward requests for resources that require authentication to a different URL and defining a different security constraint for those URLs:

<security-constraint>
<display-name>Authenticate</display-name>
<web-resource-collection>
<web-resource-name>authenticated resources</web-resource-name>
<description></description>
<url-pattern>/authenticated/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>HEAD</http-method>
<http-method>PUT</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>REGISTERED</role-name>
</auth-constraint>
</security-constraint>

getRemoteUser() still returns null. .forward() does not seem to be subject to security checks. I have found nothing in the Servlet spec that tells me what the behaviour should be.

I have three questions:

1) Is there a way I can programatically cause the authentication check?

[Currently I send my own 401 response if authentication is required. If a call to getRemoteUser() were to cause the processing of a present Authorization header, if that processing had not been done already, that would support my approach. I don't yet know if/how I could compute an appropriate challenge for the 401 responses I generate for digest authentication, which I would want to use preference to Basic authentication.]

2) Is there another way to implement discretionary access control, other than implementing my own authentication mechanism? Has anyone else solved this problem?

3) Is Tomcat's behaviour 'correct'? There may be good reason for the current interpretation of the spec, but from my point of view allowing .forward() to circumvent declared security constraints is questionable.

I am using Tomcat 6.0.29.  Sorry its such a long winded mail.

Brian



Reply via email to