quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.79k stars 2.68k forks source link

Add RoutingContext to SecurityIdentity for mTLS authentication #28326

Closed lorenzobenvenuti closed 9 months ago

lorenzobenvenuti commented 2 years ago

Description

Hi,

I'm trying to access the current request in a SecurityIdentityAugmentor. Since injecting RoutingContext doesn't seem to work (I tried with and without @ActivateRequestContext), I'm wondering if RoutingContext can be passed in a SecurityIdentity attribute. I see it's already done in OidcIdentityProvider (here) and MpJwtValidator (here). For my use case, I'd like to have the same behavior for mTLS authentication (X509IdentityProvider). If you think it's valuable, I can try to put an MR together.

Thanks,

lorenzo

Implementation ideas

MtlsAuthenticationMechanism is already adding the RequestContext to the AuthenticationRequest attributes, I think it only needs to be forwarded to the SecurityIdentity attributes in X509IdentityProvider:

X509Certificate certificate = request.getCertificate().getCertificate();
RoutingContext routingContext = HttpSecurityUtils.getRoutingContextAttribute(request);
if (routingContext != null) {
    builder.addAttribute(RoutingContext.class.getName(), routingContext);
}
QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder()
                .setPrincipal(certificate.getSubjectX500Principal())
                .addCredential(request.getCertificate())               
return Uni.createFrom().item(builder.build());
quarkus-bot[bot] commented 2 years ago

/cc @sberyozkin

sberyozkin commented 2 years ago

Hi @lorenzobenvenuti Sure, please do it

lorenzobenvenuti commented 2 years ago

It turns out that implementing this feature is harder than I thought: I didn't notice that X509IdentityProvider is defined in the quarkus-security module and it doesn't have access to RoutingContext and HttpSecurityUtils. I thought I could move attribute handling to HttpAuthenticator (that way RoutingContext will be added to SecurityIdentity attributes for all the HTTP-based authentication mechanism) but since the augmentors are invoked at the IdentityProvider level, it won't solve my issue.

I can think of different solutions, but TBH I don't like any of them.

For options 1 and 2, attributes could also be copied in IdentityProviderManager to share the logic across all the identity providers.

Thoughts?

Thanks,

lorenzo

lorenzobenvenuti commented 2 years ago

Another (hack-ish) option: add this bean to the vertx-http module

@Priority(1000)
public class RoutingContextAwareX509IdentityProvider extends X509IdentityProvider {

    @Override
    public Uni<SecurityIdentity> authenticate(CertificateAuthenticationRequest request, AuthenticationRequestContext context) {
        final Uni<SecurityIdentity> authenticate = super.authenticate(request, context);
        return authenticate.onItem().transform(
            it -> QuarkusSecurityIdentity.builder(it)
                    .addAttribute(RoutingContext.class.getName(), HttpSecurityUtils.getRoutingContextAttribute(request))
                    .build()
        );
    }

}

This is an HTTP-oriented implementation of X509IdentityProvider that will be invoked before X509IdentityProvider because of the highest priority.

sberyozkin commented 2 years ago

@lorenzobenvenuti Hi, sorry for a delay, so may be the simplest is for your application to ship such a custom provider ?

lorenzobenvenuti commented 2 years ago

Hi @sberyozkin yes, actually that's what we're doing right now. I was just wondering if someone else could benefit from moving this class to the framework, but probably it's a pretty unique use case (mTLS + need to access an header) and it's not worth the effort: if someone else needs something similar they can just write their own IdentityProvider.

Thanks,

lorenzo