[keycloak-dev] token exchange

Pedro Igor Silva psilva at redhat.com
Thu Aug 17 07:47:46 EDT 2017


I don't know Stian. We are talking about authentication and that is what
the IDToken is all about. In fact, even Google [1] has some references
about using IDTokens as a way to *authenticate* users.

There are also specs with extensions to OAuth2 that do allow usage of
*assertions" with the token endpoint [2] [3]. For instance, SAML and JWT
assertions.

[1] https://developers.google.com/identity/sign-in/web/backend-auth
[2] https://www.rfc-editor.org/rfc/rfc7523.txt
[3] https://tools.ietf.org/html/rfc7521

On Thu, Aug 17, 2017 at 2:05 AM, Stian Thorgersen <sthorger at redhat.com>
wrote:

> Actually, Bill has convinced me that ID token shouldn't be used for
> authentication. If anything a special token only available in direct grant
> should be used. The problem with ID token is that it's sent to the clients
> themselves which would effectively give all clients full access to a users
> account:
>
> * User logs in to app 1 through web flows
> * App 1 gets an access token with limited roles, but also an ID token that
> could be used for authentication
> * App 1 uses the ID token to "authenticate" itself as the user to App 2
> and can now obtain an access token with more privileges then it should
>

It depends on how you set your policies.


>
> So using ID token to authenticate a user is a completely broken concept.
>
> On 15 August 2017 at 19:51, Pedro Igor Silva <psilva at redhat.com> wrote:
>
>> We have discussed this before (I think because of Kubernetes), I don't
>> see issues about using the IDToken as a bearer for "authentication". Of
>> course, as long as you enforce validations that check if token can be
>> trusted.
>>
>> In fact, I was about to start a discussion around IDToken and signature.
>> In UMA 2.0 you can use different claim token formats to obtain a token
>> (RPT) from the token endpoint. There is a specific grant type for that. One
>> of the main changes we had in the specs.
>>
>> A common format is "http://openid.net/specs/openi
>> d-connect-core-1_0.html#HybridIDToken", which is about using an IDToken.
>>
>> On Tue, Aug 15, 2017 at 12:32 PM, Bill Burke <bburke at redhat.com> wrote:
>>
>>> I would be worried about the security implications of allowing an ID
>>> token as a way to obtain access.  If you have even one client in the domain
>>> that is not fully trusted then you are toast.  So how is it set up to make
>>> things easy?  One "master" client is defined in realm.  That client is
>>> given permission to obtain exchange for anything.  That client is marked as
>>> confidential.  Generic CLI tool is configured with client id and secret of
>>> "master" client.
>>> On 8/15/17 2:50 AM, Stian Thorgersen wrote:
>>>
>>> First of all I'm not arguing against token exchange service. It's a very
>>> useful thing IMO and I can see loads of use-cases for it. I'm just
>>> wondering about how usable it will be for the CLI tool and I'm worried
>>> about how complicated it would be to setup. If the ID token was signed that
>>> could serve as a the "identity cookie" for a CLI SSO session (if ID token
>>> is not suitable we could introduce some sort of identity token that can be
>>> used by direct grant to allow SSO sessions). Using direct grant you can
>>> then easily obtain a token for a specific client by just passing a valid
>>> "identity cookie" same way as the web browser does. Is that not simpler to
>>> setup and use?
>>>
>>> On 14 August 2017 at 15:42, Bill Burke <bburke at redhat.com> wrote:
>>>
>>>> CLI tool I wrote doesn't allow token exchange, yet, but you're correct,
>>>> I'm thinking of using it to perform token exchange.
>>>>
>>>> Our ID tokens are not signed right now.  Also you still need client to
>>>> client exchange so that you can "downgrade" a token to talk to an untrusted
>>>> service.  I've also added new fine-grain permissions "exchange-from" and
>>>> "exchange-to".
>>>>
>>>> For example, lets say Client A gets token and invokes on service B
>>>> which needs to invoke on untrusted service C.
>>>>
>>>> 1. Service B asks to exchange the token created for A to talk to C
>>>> 2. Token exchange endpoint looks at issuer, its A, so it sees if
>>>> service B has permission to "exchange-from" tokens created for A
>>>> 3. Token exchange then sees if B has permission to "exchange-to" B.
>>>>
>>>> FYI, I'm also expanding this so that you can exchange an access token
>>>> for a social provider token.  Automatic refreshes and everything if the
>>>> provider supports it.  Gonna change how client initiated linking works too
>>>> so that instead of doing the silly hash algorithm required by the call,
>>>> clients would call the exchange first, get an error response like "not
>>>> linked" that contained a browser URL that the client can use to create the
>>>> link.
>>>>
>>>> Also no reason I couldn't do the same for exchange an external token to
>>>> a internal one.  Would work the same as our IDP, import the user, etc.
>>>>
>>>>
>>>> On 8/14/17 7:06 AM, Stian Thorgersen wrote:
>>>>
>>>> I'm assuming the basic token exchange service comes from the way the
>>>> CLI tool works? I.e. you login to the tool then it allows exchanging the
>>>> token for a particular CLI client?
>>>>
>>>> Would it not be better to obtain an ID token and use direct grant to
>>>> obtain a token for the client using the ID token as the authentication
>>>> mechanism?
>>>>
>>>> On 1 August 2017 at 19:10, Pedro Igor Silva <psilva at redhat.com> wrote:
>>>>
>>>>> On Mon, Jul 31, 2017 at 1:54 PM, Bill Burke <bburke at redhat.com> wrote:
>>>>>
>>>>> >
>>>>> >
>>>>> > On 7/31/17 12:18 PM, Bill Burke wrote:
>>>>> >
>>>>> >
>>>>> >
>>>>> > On 7/31/17 11:35 AM, Pedro Igor Silva wrote:
>>>>> >
>>>>> > On Fri, Jul 28, 2017 at 5:24 PM, Bill Burke <bburke at redhat.com>
>>>>> wrote:
>>>>> >
>>>>> >> I've implemented a simple token exchange API [1] that allows you to
>>>>> >> exchange an access token created for one client to another client.
>>>>> The
>>>>> >> REST API follows the oauth token exchange api [2] very loosely.
>>>>> >>
>>>>> >> subject_token: a keycloak access token
>>>>> >>
>>>>> >> audience: takes a client id
>>>>> >>
>>>>> >> It then converts the access token created for one client and
>>>>> converts it
>>>>> >> to another.  It lives under the token endpoint.
>>>>> >>
>>>>> >> The security model is as follows:
>>>>> >>
>>>>> >> * Authenticate calling client the same way as password grant.
>>>>> >>
>>>>> >> * The calling client must have service account enabled
>>>>> >>
>>>>> >> * Service account must have a realm role "token-exchanger" grant
>>>>> edto it
>>>>> >> or, it must have a client role "token-exchanger" granted to it.
>>>>> This
>>>>> >> exchanger client role is a role defined by the target client you are
>>>>> >> exchanging the token to.
>>>>> >>
>>>>> >>
>>>>> >> Is this a good security model?  I'm thinking of not creating these
>>>>> roles
>>>>> >> right now and to enable support for exchange would require defining
>>>>> the
>>>>> >> roles specified above.
>>>>> >>
>>>>> >
>>>>> > I think roles are too coarse-grained to represent this kind of
>>>>> policy. A
>>>>> > better option would be to explicitly define the clients that are
>>>>> allowed to
>>>>> > exchange tokens for a particular resource server. Eg.:
>>>>> >
>>>>> > RS A allows Client B, C and D to exchange their tokens where the
>>>>> target
>>>>> > audience is RS A (or if using "resource", a specific resource in RS
>>>>> A).
>>>>> >
>>>>> >
>>>>> > I changed it a little.  actors are:
>>>>> >
>>>>> > * Authenticated client asking for change
>>>>> > * Clients that are the audience of the token being exchanged
>>>>> > * Client you want the token to be exchanged to
>>>>> >
>>>>> > So, the authenticated client must be in the audience of the token
>>>>> being
>>>>> > exchanged, or, have permission to exchange from that particular
>>>>> audience.
>>>>> > The authenticated client also must have permission to exchange to the
>>>>> > audience it wants to exchange to.
>>>>> >
>>>>> > Good idea to change it to use the fine grain admin permissions.
>>>>> There's a
>>>>> > couple of issues/problems with doing this that I think are easily
>>>>> done:
>>>>> >
>>>>> > * public clients can't have service accounts.
>>>>> > * Client Policy looks at kc_client_id attribute which is pulled from
>>>>> the
>>>>> > issuedFor claim in the token.  This isn't correct as we permission
>>>>> checks
>>>>> > based on the authenticated client, not the token.
>>>>> >
>>>>> > So I'll have to create a new Identity type that either wraps the
>>>>> service
>>>>> > account or ClientModel and sets the "kc_client_id" property.
>>>>> >
>>>>>
>>>>> Our policy evaluation engine is based on the claims within the token.
>>>>> The
>>>>> "issueFor" is basically the "azp" claim from OIDC. In fact, we don't
>>>>> even
>>>>> need that "kc_client_id". We could make this configurable though, and
>>>>> let
>>>>> users decide whether they want to check the "authenticated client" or
>>>>> "azp"
>>>>> ?
>>>>>
>>>>> Btw, I'm about to finish UMA Grant Type, one of the changes I'm doing
>>>>> for
>>>>> UMA 2.0. My changes will conflict with yours. Are you going to merge
>>>>> your
>>>>> changes soon ?
>>>>>
>>>>> Another thing I noticed is that maybe we could have a SPI for custom
>>>>> grant
>>>>> types. What you did and what I'm doing may justify a specific SPI for
>>>>> plugging custom grant types. Maybe too much, but maybe a nice to have.
>>>>>
>>>>>
>>>>> >
>>>>> >
>>>>> > Bill
>>>>> >
>>>>> _______________________________________________
>>>>> keycloak-dev mailing list
>>>>> keycloak-dev at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>


More information about the keycloak-dev mailing list