[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