Provide method to avoid Nimbus message parsing restrictions

Description

One example of such message parsing restriction was solved within https://shibboleth.atlassian.net/browse/JOIDC-155 by renaming the resource parameter into a custom one before handing the Nimbus HTTPRequest object to the message parser. This way we allowed spec-violating values to be used with the parameter.

noticed that similar restriction exists for client authentication parsing: Nimbus currently supports only client_secret_jwt and private_key_jwt methods for client_assertion -parameter parsing. Probably due to that they have hardcoded the parsing to check that only single JWT value may exist in client_assertion, not depending on client_assertion_type. In some cases (such as https://shibboleth.atlassian.net/browse/JOIDC-204) there might be a chain of JWTs. This parsing restriction denies wiring of such extensions.

If we provided a generic manipulation hook for the HTTPRequest object before it's passed to the Nimbus parser, the deployers could apply custom manipulation logic to avoid parsing restrictions.

Environment

None

Activity

Henri MikkonenSeptember 6, 2024 at 9:20 AM

Switched the hardcoded bean IDs to use properties instead.

  • idp.oidc.requestParser.IntrospectionRequest

  • idp.oidc.requestParser.PushedAuthorizationRequest

  • idp.oidc.requestParser.RevocationRequest

  • idp.oidc.requestParser.AuthenticationRequest

  • idp.oidc.requestParser.AuthorizationRequest

  • idp.oidc.requestParser.EndSessionRequest

  • idp.oidc.requestParser.RegisterRequest

  • idp.oidc.requestParser.TokenRequest

  • idp.oidc.requestParser.UserInfoRequest

They’re documented at https://shibboleth.atlassian.net/wiki/spaces/IDPPLUGINS/pages/3785326593/OPMessageHandling .

Henri MikkonenMay 13, 2024 at 3:03 PM

Just pushed a first version that provides what I described in the earlier comment.

The custom parsers may be wired via message-specific beans:

  • IntrospectionRequestParser

  • PushedAuthorizationRequestParser

  • RevocationRequestParser

  • AuthenticationRequestParser

  • AuthorizationRequestParser

  • EndSessionRequestParser   

  • RegisterRequestParser

  • TokenRequestParser   

  • UserInfoRequestParser

Henri MikkonenMay 13, 2024 at 3:03 PM

Having said that, if you have to do it, there is a way, by going top-down from the servlet request and tracking through the binding key we attach the PRC with. And we do it where we have to.

It’s a good hint for the custom parser developers that the PRC may be found via servlet request.

Scott CantorMay 13, 2024 at 2:48 PM

Yes, the design kind of meets in a “non-ideal” way because a lot of the code operates around PRCs but the mesaging APIs act in isolation and actually produce the MessageContext, so it’s not hooked up yet and you can’t just walk up the tree to get access to more stuff.

Having said that, if you have to do it, there is a way, by going top-down from the servlet request and tracking through the binding key we attach the PRC with. And we do it where we have to.

Henri MikkonenMay 13, 2024 at 2:40 PM

Another option could perhaps be to provide configurable hook for bean transforming HttpServletRequest into the endpoint specific message. Currently our message decoders first parse HTTPRequest from the servlet request and then hand it to the Nimbus parser. If we refactored the parsing logic to be taken from BiFunction<ProfileRequestContext,HttpServletRequest,?> “parsing strategy” (where ? refers to the expected Nimbus message object), then the building of Nimbus objects could be fully customised.


I forgot that the decoders are implementing MessageDecoder. The SWF action org.opensaml.profile.action.impl.DecodeMessage calls decoders with decode() method, so there’s no access to ProfileRequestContext.

Now it feels that the best way to provide custom parsing support with the current codebase is the following:

  • Base decoder (BaseOAuth2RequestDecoder<T extends Request>) could contain CustomNimbusRequestParser<T> customRequestParser -variable

    • It’s null by default but if it’s set, it’ll be used instead of the abstract T parseMessage() -method, which is implemented by all the implementing decoders

    • This way we don’t need to modify the inheriting classes, just the parent one

  • It makes sense to add interface CustomNimbusRequestParser<T extends Request> instead of using Function, as we probably want extensions to be able to use MessageDecodingException

    • T parse(@Nonnull final HttpServletRequest httpServletRequest) throws MessageDecodingException;

Completed
Created May 7, 2024 at 9:57 AM
Updated September 6, 2024 at 9:22 AM
Resolved September 6, 2024 at 9:22 AM

Flag notifications