Izek,

On 6/18/24 13:49, Izek Hornbeck wrote:
I am creating a Java web app (Java v17, 2021-09-14) that runs on a Tomcat
10.1.23 server. I need to authenticate users by verifying their certificate
from a smart card. (This Stack Overflow question I posted gives some good
context: "
https://stackoverflow.com/questions/78387597/what-is-the-standard-modern-way-to-use-cac-piv-card-authentication-in-java-tomca
".)

Through all the research I have done, the best way to solve this is by
using the server configuration in "server.xml". I am very new to Tomcat,
but I will try to explain everything as best as I can.

This authentication must occur after the user has entered their
credentials, so I'm thinking the best way is to redirect the user to a new
port (e.g., from 8443 to 8444) with the appropriate settings. And some
users will not be required to authenticate with a smart card certificate. I
asked another question on Stack Overflow ("
https://stackoverflow.com/questions/78624062/how-to-get-the-popup-menu-to-select-user-certificate-in-tomcat-10-server";)
that describes more of the things that I have tried specific to the server
config.

I added the command "-Djavax.net.debug=ssl" to see more details about what
was happening during the SSL handshake; I get the following:
  - javax.net.ssl|ALL|F3|https-jsse-nio-8444-exec-6|2024-06-18 10:25:02.564
MDT|X509Authentication.java:304|No X.509 cert selected for EC (and also
for EdDSA, RSA, and RSASSA-PSS)
  - javax.net.ssl|ERROR|E3|https-jsse-nio-8444-exec-5|2024-06-18
10:25:02.524 MDT|TransportContext.java:363|Fatal (BAD_CERTIFICATE): Empty
client certificate chain
  - javax.net.ssl|ERROR|E2|https-jsse-nio-8443-exec-1|2024-06-18
10:25:02.532 MDT|TransportContext.java:363|Fatal (BAD_CERTIFICATE):
Received fatal alert: bad_certificate

According to some sources (like "
https://stackoverflow.com/a/11803823/15811117";) this happens because some
certificates have not yet been added to the keystore/truststore. I have
ensured that the test client certificates and the server certificate have
been successfully added to the stores.

The two major questions I have are these:
  1) How can I get the popup menu for the user to select their certificate
and enter the smart cards pin? (Both to set up their account and for later
logins.)
  2) How do I configure my server to accept the clients' certificates?

Let me know what more information would be useful.

Starting from your SO post:

> <Connector
>     protocol="org.apache.coyote.http11.Http11NioProtocol"
>     port="8444" maxThreads="150" SSLEnabled="true"
>     maxParameterCount="1000" secure="true" scheme="https" >
>
>     <SSLHostConfig
>         sslProtocol="TLSv1.2"
>         certificateVerification="true"

You don't actually want certificateVerification="true" here, unless you want every single connection to require a certificate to be presented. Since you mentioned you need to be able to support "sign up" and also first request some other kind of authentication (username/password?) and also some resources without client-certs, this setting *must* be set to something else.

I suspect you want clientAuth="false" which is counterintuitive, but it means that the web application gets to set the policy for if/when client certs are requested.

That means that your WEB-INF/web.xml file needs to declare one or more web-resource-collection elements as requiring CLIENT-CERT authentication.

I *think* that if you have clientAuth="false" you will get the behavior you want, but you are going to have to set up some places in your application where client certs are required versus not-required. Since you are building a new application and not trying to retrofit an old one, this may be relatively easy. Here's my recommendation:

1. Unauthenticated web-resource-collection

This basically has your login informational resources that never require any authentication in order to view. That includes images, CSS, etc. No need to define any authentication constraints.

2. Semi-authenticated web-resource-collection

This is only accessible to users who have successfully logged-in using your "easy" criteria such as username+password. Probably also any pages you need to display that say "okay, now you need to register your client certificate with your account" or whatever.

For this, you must set the user-roles you will allow to view these resources. You can use any combination of roles (I recommend "*"), because unauthenticated users have no roles. You can probably use "FORM" as the authentication type if you are using e.g. username+password.

3. Fully-protected web-resource-collection

These resources are only accessible using a client certificate. After registration, or after you have determined that a user must use a client-cert after successful "simple" authentication, just forward a user to a resource in this URL space.

You just set the authentication type to CLIENT-CERT, here.

Note that Tomcat uses one of several means of user-identification when presented with a client-cert. If you have usernames that are not readily available from the information in the client-certificate, then you may have some difficulty, here.

Hopefully, this is enough to get started. I'm sure you will have some more questions and, if things get complicated (and I'll bet they will), you may need to abandon Tomcat's CLIENT-CERT authentication altogether and instead have Tomcat request the client-certificate from the browser but then *your application* will need to perform the follow-up authentication steps. This is far less convenient than having Tomcat do it, but you also have far more flexibility.

-chris

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to