Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RoutingContext to SecurityIdentity for mTLS authentication #28326

Closed
lorenzobenvenuti opened this issue Sep 30, 2022 · 6 comments · Fixed by #38266
Closed

Add RoutingContext to SecurityIdentity for mTLS authentication #28326

lorenzobenvenuti opened this issue Sep 30, 2022 · 6 comments · Fixed by #38266
Labels
area/security kind/enhancement New feature or request
Milestone

Comments

@lorenzobenvenuti
Copy link

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());
@lorenzobenvenuti lorenzobenvenuti added the kind/enhancement New feature or request label Sep 30, 2022
@quarkus-bot
Copy link

quarkus-bot bot commented Sep 30, 2022

/cc @sberyozkin

@sberyozkin
Copy link
Member

Hi @lorenzobenvenuti Sure, please do it

@lorenzobenvenuti
Copy link
Author

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.

  • Option 1: define the mappings between AuthenticationRequest and SecurityIdentity somewhere; for example, introducing an AttributeMapper interface that declares a Map<String, String> getAttributeMappings() method. X509IdentityProvider could inject a Instance<AttributeMapper> and, if present, copy all the attributes defined in the mappings. Then, the HTTP extension could add an AttributeMapper implementation to the context, mapping quarkus.http.routing.context to RoutingContext.class.getName().

  • Option 2: same as above, but passing the mappings in an attribute. MtlsAuthenticationMechanism can add a quarkus.security.attributes attribute to the AuthenticationRequest, containing a Map<String,String>, and X509IdentityProvidercan read that attribute and copy the other attributes to theSecurityIdentity` instance

  • Option 3, really ugly hack: read/write the attribute using strings to avoid requiring an explicit dependency, i.e.

      /* In X509IdentityProvider */
      QuarkusSecurityIdentity.builder()
        /* ... */
        .addAttribute(
          "io.vertx.ext.web.RoutingContext",
          request.getAttribute("quarkus.http.routing.context")
        )
        /* ... */

    Just kidding, I refuse to write this code :-D

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
Copy link
Author

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
Copy link
Member

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

@lorenzobenvenuti
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment