[keycloak-dev] client requested account linking

Bill Burke bburke at redhat.com
Sat Feb 25 19:45:39 EST 2017


You mean an keycloak auth flow?  I was thinking the same thing. Or do 
you want to know how the HTTP request flow is?

1. Redirect from client:

Location: 
https://keycloak/auth/realms/{realm}/broker/{providerId}/link?client_id={id}&redirect_uri={uri}&nonce={nonce}&hash={hash}

2. Server extracts SSO cookie from GET request to obtain UserSession.  
Validates client_id and redirect_uri.  Calculates and validates hashes.

3. Do regular account link logic that already exists

4. Redirect to social provider

5. Redirect Back to Keycloak

6. Redirect to "redirect_uri" provided in step #1


On 2/25/17 6:58 PM, Scott Rossillo wrote:
> Bill,
>
> Can you provide a browser flow of what you’re trying to accomplish?
>
> Scott Rossillo
> Smartling | Senior Software Engineer
> srossillo at smartling.com <mailto:srossillo at smartling.com>
>
>> On Feb 25, 2017, at 9:42 AM, Bill Burke <bburke at redhat.com 
>> <mailto:bburke at redhat.com>> wrote:
>>
>> Ok, I changed this again.  Any solution we come up with will require
>> that the application protect itself from CSRF for this operation.
>> There's nothing really the server can do. We can give guidelines on how
>> to accomplish this.  So, instead of this handshake, there will only be
>> one GET request to a link url that takes client_id, redirect_uri, nonce,
>> and hash query parameters.
>>
>> The nonce will be a random string sent by the client.  The hash will be
>> a base64url encoded SHA_256 hash of nonce + clientSessionId.  The server
>> will verify this hash by looking for an SSO cookie, matching it up with
>> a UserSession, then looping through ClientSessionModels to find a
>> matching clientId then creating and matching the hash.  This is combined
>> with not allowing CORS preflight requests to this URL  (protects SSO
>> cookie) as well as checking that any Origin header matches the client.
>> I think this is enough to ensure that this server URL is protected from
>> direct CSRF attacks.
>>
>>
>> On 2/24/17 8:46 PM, Bill Burke wrote:
>>> Ok, option #3 where I would pass an access token to initiate the link
>>> won't work as the access token could be leaked by a CSRF attack on the
>>> client.  My new solution is to do a custom protocol.  The goal of this
>>> protocol is for the server to verify that the client initiated the
>>> account link and not some rogue site.
>>>
>>> 1. Client does a background bearer-token authenticated to the Keycloak
>>> operation /initiate-link using the access token it got from login.
>>>
>>> 2. /initiate-link gets the ClientSessionModel associated with the
>>> bearer-token. It generates a server-nonce and stores it within the
>>> ClientSessionModel.
>>>
>>> 3. keycloak /initiate-link returns a response that contains the 
>>> server-nonce
>>>
>>> 4. Client generates its own client-nonce.  This client-nonce is stored
>>> in its HttpSession.
>>>
>>> 5. Client generates a nonce-hash of server-nonce + client-nonce +
>>> provider-id.
>>>
>>> 6. Client redirects the browser to Keycloak /link operation passing the
>>> client-nonce, nonce-hash, provider-id, client-id, and redirect-uri as
>>> query parameters.
>>>
>>> 7. Keycloak /link operation validates that the browser is logged in.  If
>>> the user is not logged, an error page is shown.  We DO NOT redirect back
>>> to the client when there is an error as this is an attack vector.
>>>
>>> 8. Keycloak verifies clientid, redirect uri, and provider id.
>>>
>>> 9. Keycloak loops through the browser's UserSessionModel looking for
>>> ClientSessionModels that match the clientId.  Checks to see if this
>>> ClientSession has a server-nonce within it.  If so, it validates the
>>> hash.  We DO NOT redirect back to the client when there is an error as
>>> this is an attack vector.  The server-nonce client session attribute is
>>> cleared so that it can only be used once.
>>>
>>> 10. Keycloak initiates the social provider login
>>>
>>> 11. Keycloak redirects back to the client using the redirect_uri
>>>
>>> What isn't protected here is the client.  If the client is a traditional
>>> web app, the client is responsible for protecting itself from CSRF.  The
>>> Account Service does this with a cookie nonce plus the nonce in the
>>> rendered page links, and it also rejects any CORS requests.  The client
>>> app will have to do this too.  I don't think Javascript apps are
>>> affected unless there is a URL you can redirect to that triggers 
>>> this flow.
>>>
>>> Again, I'm not even sure we have to do this sort of thing.  All a CSRF
>>> attack could do is request that the user link their Keycloak account.
>>> The attacker can't get any information about the user.
>>>
>>>
>>>
>>> On 2/24/17 9:10 AM, Bill Burke wrote:
>>>> Account linking *MUST* be browser based as you need to delegate
>>>> authentication to the IDP you are brokering with.
>>>>
>>>>
>>>> On 2/24/17 3:21 AM, Marek Posolda wrote:
>>>>> Don't we have a plan to rewrite AccountService to use Angular+REST? If
>>>>> yes, then we are fine though. We will have REST endpoint for link
>>>>> broker, which can be invoked with the bearer token as long as the
>>>>> token has "manage-account" scope. We don't need to care about CSRF 
>>>>> then.
>>>>>
>>>>> I can see the only reason to keep support browser+cookie based flows -
>>>>> the case when client application doesn't have Keycloak token. But from
>>>>> what you mentioned in the last paragraph, it looks that their client
>>>>> has our access token?
>>>>>
>>>>> Marek
>>>>>
>>>>>
>>>>> On 23/02/17 23:24, Bill Burke wrote:
>>>>>> A customer has asked us to implement a feature in which there is a
>>>>>> browser endpoint on keycloak.  This URL can be told to link to a
>>>>>> specific identity broker provider (Google, Facebook, etc.) and 
>>>>>> then the
>>>>>> browser would be redirected back to the client. Pretty much what 
>>>>>> exists
>>>>>> in the Account Service console, but without having to look at the
>>>>>> Account Service.  The reason for this is that they are doing 
>>>>>> integration
>>>>>> with a specific social provider and don't want to have to go 
>>>>>> through the
>>>>>> Account Service pages. Seems pretty reasonable and valid use case...
>>>>>> I'm worried about a couple of things:
>>>>>>
>>>>>> * The design of it
>>>>>>
>>>>>> * The security implications.
>>>>>>
>>>>>> The implementation would be simple enough, it would just extract code
>>>>>> from the accoutn service.  The endpoint would take a "providerId"
>>>>>> paramter that would be the idp linking to, a "clientId" for the 
>>>>>> client
>>>>>> requesting the link, and a "redirect_uri" to redirect back to 
>>>>>> after the
>>>>>> link is successful. Obviously the redirect_uri would be validated
>>>>>> against the clientId.
>>>>>>
>>>>>> Now comes the interesting part, the security implications. Account
>>>>>> linking in the Account Service is fine and dandy and doesn't have any
>>>>>> security holes because we guarantee that the Account Service 
>>>>>> initiated
>>>>>> the linking via a CSRF check.  For this new Client-Requested-Linking
>>>>>> feature, if we do nothing, and just model it as above, we cannot
>>>>>> guarantee that the client initiated the linking request.  What 
>>>>>> are the
>>>>>> implications of this?  This feature would be vulnerable to CSRF.  A
>>>>>> rogue website could initiate account linking to a specific configured
>>>>>> provider.  Is this bad?  I don't know.  We can guarantee that the
>>>>>> redirect uri is valid.  The browser would never get back to the rogue
>>>>>> website. So what can we do to improve this?
>>>>>>
>>>>>> * We could do nothing and hope its ok that anybody can initiate a 
>>>>>> link.
>>>>>>
>>>>>> * We could add a consent screen like this: "Application 'clientId' is
>>>>>> requesting that you link your user account to 'providerId'.  Do you
>>>>>> agree to this?  You will be redirected to this provider if you click
>>>>>> ok.".  This of course relies on the user to actually read the 
>>>>>> page.  Is
>>>>>> this good enough?
>>>>>>
>>>>>> * My last thought would be OIDC specific.  We could use the POST 
>>>>>> binding
>>>>>> trick that SAML does to do a browser redirect via a POST call. 
>>>>>> THe POST
>>>>>> would contain the access token the client has.  We match this 
>>>>>> token up
>>>>>> against the browser cookie to make sure its the same session. We also
>>>>>> make sure that the access token has permission to request a link. 
>>>>>>  There
>>>>>> are 2 downsides to this approach a) This requires some code on the
>>>>>> client side to obtain the access token and then to package it up 
>>>>>> into an
>>>>>> HTML document so the POST binding trick can be done.  b) This 
>>>>>> will only
>>>>>> work for OIDC clients.  SAML clients will be left in the dust, 
>>>>>> although
>>>>>> I guess we could allow SAML to push a signed assertion back.
>>>>>>
>>>>>>
>>>>>> Thoughts?
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> keycloak-dev mailing list
>>>>>> keycloak-dev at lists.jboss.org <mailto:keycloak-dev at lists.jboss.org>
>>>>>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>>>> _______________________________________________
>>>> keycloak-dev mailing list
>>>> keycloak-dev at lists.jboss.org <mailto:keycloak-dev at lists.jboss.org>
>>>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>>> _______________________________________________
>>> keycloak-dev mailing list
>>> keycloak-dev at lists.jboss.org <mailto:keycloak-dev at lists.jboss.org>
>>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>>
>> _______________________________________________
>> keycloak-dev mailing list
>> keycloak-dev at lists.jboss.org <mailto:keycloak-dev at lists.jboss.org>
>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>



More information about the keycloak-dev mailing list