On 3/15/17 7:24 AM, Pedro Igor Silva wrote:
From externl to Keycloka:
This would be a form POST to /token/convert-from with these additional
form parameters
"token" - REQUIRED. string rep of the token
"provider" - REQUIRED. id of transformer register in the realm for the
token type
Why you need to send "provider" ? If you are already sending
"requested_token_type", the provider is implicit, right ?
Or if you don't send "requested_token_type" you can allow users to
specify the default token type to be issued.
provider matches up with a Keycloak ComponentModel which matches up to a
Keycloak ProviderFactory which knows how to do the translation. Need
some way of finding the service that can handle the translation of the
external token.
The requested_token_type in my proposal is the catagory of token you
want, not its actual type
"requested-token-type" - OPTIONAL. "id",
"access", "offline", or
I think we have a great opportunity here to also support use cases
where you need to exchange a SAML assertion with an OAuth2/OIDC token.
There is a specific standard for that, but I think a STS would be
perfect for this.
I remember some people asking for this and I think it will be a great
win for enterprise use cases and legacy systems.
I still think we should have a separation between external and internal
exchanges.
"refresh". Default is "access".
"scope" - OPTIONAL. Same as oauth scope.
This operation is analogous to the code to token flow. Here we are
creating a token tailored to the authenticated client. So all scope
configurations and mappers that the client has are applied. This means
that the client must be registered as an OIDC client. The SPI
would look
something like this:
interface TokenExchangeFromProvider extends Provider {
Transformer parse(ClientModel client, Map<String, String>
formParameters);
interface Transformer {
UserModel getUser();
IDToken convert(IDToken idToken);
AccessToken convert(AccessToken accessToken);
}
}
The getUser() method returns a user that was authenticated from the
external token. The convert() methods just gives the provider the
flexibility to do further transformations on the returned token.
The runtime would do something like this:
ClientModel authenticatedClient = ...;
ComponentModel model = realm.getComponent(formParams.get("provider"));
TokenExchangeFromProvider provider =
session.getProvider(TokenExchangeFromProvider.class, model);
Transformer transformer = provider.parse(formParams);
UserModel user = transformer.getUser();
if (formParam.get("requested-token-type").equals("access")) {
AccessToken accessToken = generateAccessToken(authenticatedClient,
user, ...);
accessToken = transformer.convert(accessToken).
}
Something similar would be done for converting a Keycloak token to an
external token:
This would be a form POST to /token/convert-to with these additional
form parameters
"token" - REQUIRED. string rep of the token
"provider" - REQUIRED. id of transformer register in the realm for the
token type
Same comments I did to "external to Keycloak" exchange. In this
particular case, I think we can also provide some integration with
identity brokering functionality.
For instance, suppose I have a KC token and I want to obtain a
Facebook AT. I know we have ways to do that today, but I think that
using a STS is much more neat. In this case, we also don't need to
send the provider, but we can make this completely configurable from
admin console. E.g.: associate token types with a OOTB/custom identity
providers. Maybe we can even define a Token Exchange Identity
Provider, which can be configured to integrate with an external STS.
An STS could
be used to convert a Facebook AT into a Keycloak one, but
not vice versa. For Facebook, Google etc. a browser protocol is
required in many cases to obtain the external token. With Identity
Brokering you are delegating authentication to another IDP. Keycloak
doesn't know how the user will be authenticated. For instance, with
Google a user may require authentication via SMS. FYI, this is why the
"Client Initiated Account Linking" protocol was just implemented.
There's also a lot of brokers that can only do logout via a browser
protocol.
I see what you mean though. We already have the beginnings of an STS
that is spread out in different classes and services.
interface TokenExchangeToProvider extends Provider {
ResponseBuilder parse(ClientModel client, Map<String, String>
formParameters);
}
Since we're crafting something for an external token system, we
give the
provider complete autonomy in crafting the HTTP response to this
operation.
Not sure you remember. But when we were discussing SAML on the earlier
days of Keycloak, I mentioned a API for Security Token Service that we
had in PL for years (I think Stefan did it). Plus a simplified version
of this API in PL JEE/IDM. One of the things that I liked most in PL
is that the STS is the backbone for the IdP. What I mean is, the IdP
don't care about how a token is issued/revoked/validated/renewed, but
delegate this to STS. Being responsible to basically implement the
communication/protocol between the involved parties.
We already have this separation. Authentication is independent of
protocol and we have a common data model that isn't protocol specific.
We also do not map from a brokered SAML assertion to a client's OIDC
access token. The brokered SAML assertion is mapped into a common data
model which is then mapped to the OIDC access token.
I see what you are saying though. Token Exchange should be done in
conjunction with refactoring and rewriting the Identity Brokering SPI as
the two are related. This also probably has an effect on Client
configuration as I could see an STS-only based client that is just
interacting with the STS.
Bill