-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Token exchange - added experimental token exchange V2 divided into mu… #36407
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
Token exchange - added experimental token exchange V2 divided into mu… #36407
Conversation
6f706d2 to
3bf5a96
Compare
rmartinc
left a comment
There was a problem hiding this 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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 likeParameter 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 parameterrequested_subject, which is not allowed for "standard" . -
In case that check would be in the
supports()method like you suggested, he will see errorNo 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
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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-authzI'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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 :-)
…ltiple features closes keycloak#35504 Signed-off-by: mposolda <[email protected]>
Signed-off-by: mposolda <[email protected]>
3bf5a96 to
bf13376
Compare
rmartinc
left a comment
There was a problem hiding this 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!
|
@rmartinc Thanks! |
…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:
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 methodsupports(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 methodtokenExchange()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).