Question about Spring Security with Webflux.
I have a SpringBoot Webflux web app with Spring Security. The same app also have SSL Server enabled with keystore and truststore for two way SSL, mTLS.
At this point, already, clients trying to request endpoints from my app are failing if they do not have the correct client certificate, this is great! Nothing done on the app layer, just configuring the keystore and truststore, amazing.
Question: Is it possible to further authorize who can access a particular endpoint based on the client certificate itself?
By that I mean, maybe with Spring Security, a client client1 coming with a valid client certificate want to request /endpointA will be able to access it if the certificate has a correct CN. But client2 will be rejected to request /endpointA if client2 has the wrong CN.
Vice versa, client A who has the wrong CN will not be able to request /endpointB, only available to client2 that will have the good client2 CN.
And of course, if client3 has the incorrect CN for both /endpointA and /endpointB, client3 will not be able to request any of those (but he has a valid client certificate).
Would it be possible to provide example with Spring Webflux, (not MVC) please? Finally, if this possible? How? (code snippet will be great).
Thank you
Yes this is possible. You can even further secure your web application by validating the CN field of a certificate and block it if it doesnt has the correct name. I am not sure if this is possible with Spring Security out of the box, but I know it is possible with AOP by using AspectJ. In this way you can intercept the request after a succesfull ssl handshake and before it enters your controller. I would definitely advise to read this article: Intro to AspectJ as it would help you to understand the basic concept of the library.
What you can do is create an annotation, for example: AdditionalCertificateValidations which can take a list of allowed and not allowed common names. See below for an implementation. In this way you can decide on every controller which CN you want to allow and not allow.
Afterwords you can annotate your controller with the above annotation and specify the common names:
Now you need to provide an implementation for the annotation. The actual class which will intercept the request and also validate the certificate content.
With the above configuration a client with the allowed common name will get a 200 status code with the hello message and other clients will get a 400 status code with the message: This certificate is not a valid one. You can use the above options with the following additional library:
The example project can be found here: GitHub - Java Tutorials
The example code snippets can be found here:
=============== update 1#
I discovered that the CN name can also be validate with only spring security. See for detailed explanation with examples here: https://www.baeldung.com/x-509-authentication-in-spring-security#2-spring-security-configuration
First you need to tell spring to intercept every request, authorise and authenticate by overriding the
configure
method with your own logic, see below for an example. It will extract the common name field and treat it as a "User Name" and it will check with the UserDetailsService if the user is known. Your controller also needs to be annotated with@PreAuthorize("hasAuthority('ROLE_USER')")
=============== update 2#
I somehow missed the point it should be in a non-blocking fashion. The reactive flow is kinda similar to the example provided within the first update above. The following configuration would do the trick for you:
I created a working example implementation based on the above input, see here for the details: GitHub - Spring security with common name validation