Question

I have a web app running in Tomcat. I want to permit any user with a valid cert trusted by the server to access the web app, but I want to read the user's DN from the cert. I configured the SSL connector with clientAuth="true" ("want" also works) and the web.xml has a login-constraint requiring a client cert to be presented. I configured a truststore with a CA cert used to sign the user certs.

The client presents a cert and the server accepts it, permitting access to the app. My problem is that when I call getUserPrincipal() on the HttpServletRequest instance, it is null. If I add an auth-constraint to web.xml, requiring the user to be in a certain role, and the user is configured to be in the specified role, then the user principal is not null.

The API for HttpServletRequest says that the user principal will be null if the user is not authenticated. I consider the user to be authenticated since they have presented a valid and trusted cert, but apparently authentication in this context includes authorization?

Is there any way I can get access to the user principal from a valid trusted cert, without assigning the user to a specific role?

Here is the web.xml snippet which results in the principal being null:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>My App</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
</security-constraint>
<login-config>
    <auth-method>CLIENT-CERT</auth-method>
    <realm-name>My Realm</realm-name>
</login-config>

And here is the web.xml snippet which enables me to get the user principal when the user is configured for the specified role:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>My App</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>Some Role</role-name>
    </auth-constraint>
</security-constraint>
<login-config>
    <auth-method>CLIENT-CERT</auth-method>
    <realm-name>My Realm</realm-name>
</login-config>
<security-role>
    <role-name>Some Role</role-name>
</security-role>
Was it helpful?

Solution

I discovered that although HttpServletRequest#getUserPrincipal() returns null for the situation I described (user authenticated, but no authorization required or attempted), ServletRequest#getAttribute("javax.servlet.request.X509Certificate") returns an array of certs which contains the cert of the authenticated user.

This solves my problem, but it still seems to me that the behavior of HttpServletRequest#getUserPrincipal() is not in accordance with the API, which says "Returns a java.security.Principal object containing the name of the current authenticated user". There is no mention that an explicit authorization constraint must also be applied and satsified, but that seems to be the way Tomcat has implemented it.

OTHER TIPS

Tomcat won't ask for the certificate unless either it is configured to require it for all connections or the resource being requested requires a specific role.

So your statement that the user has presented a certificate is not correct.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top