6

I am working on a project where I need to create an application that shall act as an OIDC mediator between a client which only supports OIDC for authentication and a REST api. The REST api is able to generate tokens and give user info but does not support OIDC.

To achieve this I am thinking of using keycloak to handle the OIDC communication with the client and implement my own java application that keycloak can trigger to realize the authorization, token and userinfo endpoint (sort of a custom ownmade identity provider) handling the communication with the rest api.

I have created a realm in keycloak and configured the realm to use an Identity Provider Redirector with an Identity Provider I added in keycloak (user-defined OpenID Connect v1.0). In the identity provider configuration I have set all the URLs to point to my java application but the initial OIDC authorization call from the client just redirects to the redirect_uri with a #error=login_required without any of my endpoints in the java application beeing triggered.

I guess there is something I have missed.. I need to intervene the authorization flow so that I can pick up a query param from the authorization request that needs to be handled in my java application. I also need to map the token from the rest api into the token request (when this request comes from the backend of the client app), and finally map the userinfo object as a response to the userinfo request.

I really hope someone have time to point me in the right direction. Thank you so much in advance.

Edit: I have added a sequence diagram to explain it better: enter image description here

I need to intercept the authorization request call to pick up a custom query param (endUserString) that identifies the user. There will be no user login form. I need the param in my code that uses this towards the REST API. Both the token and the userinfo must be received from my APP and not from keycloak itself.

The Java Mediator may ask for a token in advance (A) and use this to access the Rest API (using a predefined clientId and clientsecret). Alternatively this token may be fetched for each method. To token must be used to retrieve customer info from the REST API (B). I want to wrap this with OIDC support without any login form. A browser will just redirect to the authorization flow with the endUserString identifying the end user. The customer info will be returned from the java mediator into keycloak responding this in the GetUserInfoRsp.

Tomas Andersen
  • 289
  • 1
  • 4
  • 13
  • I am missing a point in your solution: why use Keycloak as a proxy to your homemade OIDC provider/facade? Why not plug the client directly to your homemade OIDC provider? – Allan Jun 17 '20 at 06:58
  • Hi @Allan. I was thinking that maybe keycloak could handle refresh tokens and everything like that and that I just exposed some "helper" methods in my application to do the rest calls to the API. Or that I might just create some java code that could be added in keycloak as a library. – Tomas Andersen Jun 17 '20 at 10:08
  • I am sorry but your question is too vague for me to be able to help you. Maybe you should try adding details regarding the REST api, the client and the workflow you foresee. If it can help, here are the test cases of Keycloak which generate the `login_required` error: https://github.com/keycloak/keycloak/blob/master/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerPromptNoneRedirectTest.java#L58 – Allan Jun 18 '20 at 06:29
  • Hi. I have updated my post to try to explain things better. Thank you so much for your time. – Tomas Andersen Jun 19 '20 at 09:55
  • Wow! That's a lot better, well done for the edit! – Allan Jun 19 '20 at 13:04

1 Answers1

7

I think there might be a simpler solution than what you envisioned: implementing your own custom authenticator for Keycloak.

Keycloak has a notion of authentication flow which is a tree of authenticators than are provided by Keycloak or custom made. Each authenticator can be called to try to authenticate the user.

The most common one is the Username/Password Form which displays a login page to the user and authenticates the user if the provided credentials are valid. But you could imagine any type of authenticator such as an SMS authenticator or a magic link one.

You can find the existing Keycloak's authenticators on their repo and the documentation on how to create your own here.

In your case, you would need to implement your own logic where your authenticator would get the endUserString param from the request and call the REST API to validate the user's identity. You could fetch the REST API token at initialisation or for each request. You could also modify the user stored in Keycloak with data coming from the REST API's user info endpoint (common OIDC attributes or custom attributes).

Please note that the dev team announced Keycloak X, a sort of reboot of the project which will probably bring breaking changes to their APIs.

Also, please consider all the security impacts of your design as, from what you provided, it seems the authentication of a user will only rely on a simple query parameter which, if it doesn't change over time for example, feels like a big security hole.

Allan
  • 177
  • 1
  • 5
  • Thank you so much for your input. I will look into this and see if I can find a way to implement my own custom authenticator. About the security impacts we are fully aware and did do some risk analysis. The customer accepts the solution as secure enough as this is not protecting any sensitive data. We just need to get things working. In the long term we are planning better ways to manage this. Thanks again! – Tomas Andersen Jun 19 '20 at 14:15
  • Hi again Allan. Just wanted to thank you again for your input. We got a solution up and running in August. About the security impact you warned about, we made the user query param different for every request. I ended up using the Magic link authenticator as a template for creating a new custom authenticator. By adding this to the browser flow I get keycloak to handle the OIDC flow for me and I am able to populate the userinfo params from the custom authenticator calling the REST api to get it. – Tomas Andersen Nov 09 '20 at 14:26
  • Happy it helped :) – Allan Jan 20 '21 at 15:00