Let authenticators create normalized subject attributes
Preflight checklist
- [x] I agree to follow this project's Code of Conduct.
- [x] I have read and am following this repository's Contribution Guidelines."
- [x] I have discussed this feature request with the community.
Describe the background of your feature request
In our project we use heimdall as a proxy in front of our backend upstream service to handle different types of authentication (API Token, OAuth2 Client Credentials, OIDC, proprietary JWT, ...). In the finalize phase of the pipeline, we generate a new token to be sent to the upstream service. The new token contains the relevant information of the original token in a normalized form. So, regardless of which type of authentication was provided and how the original token looks like, the token that is sent to the upstream always has the same format.
The Problem
The only place where this kind of normalization can be done, is in the finalizers. We have mainly two options:
- define one finalizer for the upstream token - that finalizer has to identify and handle all different tokens formats (might get very complex)
- define one finalizer per authenticator/original token - all of them create the same upstream token format
We decided to follow the second option. To decide which finalizer to use, each of them tries to identify the format of the token using if-clauses like
if: |
has(Subject.Attributes.email)
&& Subject.Attributes.email.contains("@acme.com")
As those if-clauses are part of the rules, not of the finalizer mechanism itself, we have to duplicate them in every rule that uses the authenticator/finalizer tuple.
Describe your idea
As we already have dedicated authenticators for the different authentication types and token formats, it would be great if those authenticators could fetch the relevant attributes from their token and already do the normalization by providing a new set of normalized attributes.
e. g.
- authenticator 1 handles token which contains the attribute
preferredUsername - authenticator 2 handles token which contains the attribute
client_id - both authenticators provide the values of these two attributes in a new attribute like
Subject.NormalizedAttributes.name
In this case we would only need one very simple finalizer which creates the upstream token based on the normalized attributes. I guess that, beside the finalizer, also contextualizers and authorizers could benefit from this normalized attributes.
Are there any workarounds or alternatives?
As written before
- having one complex finalizer
- having multiple finalizers, one per authenticator
Version
0.16.7
Additional Context
No response
Thank you @torstenmandry for this ticket/idea. I think this normalization is pretty essential and can simplify many setups. Therefore, I'll try to include the corresponding functionality in the upcoming release.
Here my current idea on how it could be addressed:
As of today all authenticators which set the Subject.Attributes property allow doing so via a gjson expression. Same is also true for the actual Subject.ID:
subject:
id: <expression to extract the subject id>
attributes: <expression to extract the attributes>
The limitation of gjson is that one can extract a single object from the payload returned by the used IDP.
We could change that in a way that the configuration of the attributes property could also be a map in addition to a string. That way, one could also do the following:
subject:
id: <expression to extract the subject id>
attributes:
email: <expression to extract the email>
username: <expression to extract the user name>
And the resulting Subject object would look like
Subject = {
ID: "<some id>",
Attributes: {
email: "...",
username: "..."
}
}
If not configured, the behavior would be the same as already given today. And if there is a need to include all received attributes in addition to the normalized ones, one could simply make use of the special @this expression (also available today). So something like this:
subject:
id: <expression to extract the subject id>
attributes:
email: <expression to extract the email>
username: <expression to extract the user name>
# ... further key value pairs
all: @this
This way there is no need to introduce an additional property NormalizedAttributes as suggested by you.
Do you maybe have any concerns with that approach?
No, I have no concerns. Sounds reasonable for me and will solve our problem.
Thank you for your quick reply and for prioritizing my request.