Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@mposolda
Copy link
Contributor

@mposolda mposolda commented Jan 13, 2025

…ltiple features

closes #35504

PR keeps the feature "token-exchange" as a preview feature, which is dedicated for all 3 use-cases of token-exchange as of today (standard, federated, subject impersonation).

But PR introduces "token-exchange V2" feature. It introduces 3 separate features for it:

  • token-exchange-standard V2 (Standard token-exchange, which we aim to promote to supported and which is compliant with the specification https://datatracker.ietf.org/doc/html/rfc8693 )
  • token-exchange-federated (Federated token exchange for the use-cases with identity proviers. Both external-internal and internal-external covered)
  • token-exchange-subject-impersonation (Subject impersonation token exchange including "Direct naked impersonation").

the point of introducing V2 features is the ability to do new development and at the same time not break the current token-exchange (in case that we don't fully achieve to make it supported in 26.2 etc).

The 3 new "V2" features are experimental for now. The aim is to support token-exchange V2 and then possibly follow with the other V2 features. The token-exchange V1 will be deprecated/removed at some point (once V2 features are either supported or preview).

Regarding implementation, I've did dedicated providers for every feature, but they all inherit from AbstractTokenExchangeProvider, which has most of the methods re-usable by all providers. The method supports(TokenExchangeContext) is implemented differently for each provider as it tries to detect which type of token-exchange request it is (based on the parameters used). Also method tokenExchange() is implemented for each provider separately. The V1 implementation is exactly the same as it was before and supports all 3 types of token-exchange requests (standard, federated, subject impersonation).

Regarding tests: I've re-used the existing tests,l but make sure they are tested with both V1 and V2. Some abstract classes introduced to make sure same tests can be re-used by both V1 and V2 implementations. I assume that for the future, we may need to remove abstract classes (or move most of other tests to either V1 or V2) according to when the development on V2 starts and the implementation will start to differ between V1 and V2.

The V2 token-exchange still uses fine-grained-admin-permissions V1 for now (that will probably change in the follow-up PRs to use fine-grained admin permissions V2).

@mposolda mposolda self-assigned this Jan 13, 2025
@mposolda mposolda force-pushed the 35504-token-exchange-features-rebase branch 3 times, most recently from 6f706d2 to 3bf5a96 Compare January 16, 2025 08:01
@mposolda mposolda marked this pull request as ready for review January 16, 2025 08:59
@mposolda mposolda requested review from a team as code owners January 16, 2025 08:59
Copy link
Contributor

@rmartinc rmartinc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mposolda For the moment v1 and v2 are exactly the same, but v2 is divided in different profiles. The idea will be adding modifications to v2 after this PR and both versions will start to differ. Right?

Just added two little comments for your consideration which are not very important. Approving anyway.


@Override
public boolean supports(TokenExchangeContext context) {
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the v2 standard profile is enabled alone (nor federated, neither impersonation) this will manage all the requests even if they contains parameters for the other requests. Some of the possible combinations will return a token (for example for the client instead of the external IdP, or for the same user instead of the impersonated user). What do you think about checking for the presence of those parameters too in this provider? Something like:

String requestedIssuer = context.getFormParams().getFirst(OAuth2Constants.REQUESTED_ISSUER);
String requestedSubject = context.getFormParams().getFirst(OAuth2Constants.REQUESTED_SUBJECT);
return requestedIssuer == null && requestedSubject == null;

Federated external to internal will fail because of signature, but we can check it too if you like.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I was thinking exactly about that before as well. In the end, I've added the check directly to the tokenExchange() method itself in case that those parameters are present: https://github.com/keycloak/keycloak/pull/36407/files#diff-d6af3e4db00e3f2e9ce210ddbd14152aab83f0dd584411ae918110e9e1912c5aR91-R103 .

My thinking was this: Assuming that only "standard" is enabled and "federated" is disabled and "impersonation" is also disabled. And customer uses for example requested_subject parameter. Then:

  • In case the check is in the tokenExchange() method, customer will see the error like Parameter requested_subject is not supported . When he sent this error to us, we will see immediately from this error message what is going on. We will see the fact that he enabled just "standard" and used parameter requested_subject, which is not allowed for "standard" .

  • In case that check would be in the supports() method like you suggested, he will see error No token exchange provider available . When he send this error to us, it is slightly less clear what is going on (we will need to ask for the parameters, startup command for enabled features etc).

So that is the only reason for adding to tokenExchange() :-) But maybe it has some other disadvantages... Like conceptually it is maybe better to have it in supports() ? Not sure...

If you prefer, I can move to supports() . Not strong on this... Just added my points

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! Yes, I didn't detect the tokenExchange was doing those checks. It's OK, I just wanted to return an error and this solution is even better because it directly says that the option is not supported.

TOKEN_EXCHANGE("Token Exchange Service", Type.PREVIEW, 1),
TOKEN_EXCHANGE_STANDARD_V2("Standard Token Exchange version 2", Type.EXPERIMENTAL, 2, Feature.ADMIN_FINE_GRAINED_AUTHZ), // TODO: Switch v2 token exchanges to depend admin-fine-grained-authz-v2
TOKEN_EXCHANGE_FEDERATED_V2("Federated Token Exchange for external-internal and internal-external token exchange", Type.EXPERIMENTAL, 2, Feature.ADMIN_FINE_GRAINED_AUTHZ),
TOKEN_EXCHANGE_SUBJECT_IMPERSONATION_V2("Subject impersonation Token Exchange", Type.EXPERIMENTAL, 2, Feature.ADMIN_FINE_GRAINED_AUTHZ),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although the version is 2 for the new token exchange features, the name is different, so you can start the server like this for example:

./kc.sh start-dev --features token-exchange,token-exchange-standard,token-exchange-federated,admin-fine-grained-authz

I'm not saying this is an error but at least we can increase the order of the new v2 standard factory to 1 to be tried before the v1 version.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isAvailable can also be used to avoid the two features are enabled at the same time

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rmartinc Thanks for pointing that. I've updated the PR (added additional commit just for the easier review what changed).

I've used the approach with order() . The approach with isAvailable in profile might be possible too, but will probably require some updates in the Profile class itself (due the isAvailable is called before Profile is initialized, so it is not easily possible to ask for other enabled features). So rather went the easier path for now :-)

@mposolda mposolda force-pushed the 35504-token-exchange-features-rebase branch from 3bf5a96 to bf13376 Compare January 16, 2025 17:24
Copy link
Contributor

@rmartinc rmartinc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes and the explanation. Approved without ant comments now!

@mposolda
Copy link
Contributor Author

@rmartinc Thanks!

@mposolda mposolda merged commit ec5a8d1 into keycloak:main Jan 17, 2025
77 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Divide token-exchange to multiple features

2 participants