Keycloak SSO integration doubts

357 views
Skip to first unread message

Roman Pierson

unread,
Aug 23, 2017, 7:29:18 AM8/23/17
to vert.x
Hi

I just started to try out Keycloak as SSO provider as it looks very promising. I basically tried out first what Paulo explained in a video once and it works very well. However trying to dig in deeper into the topic I I have some uncertainities and doubts that probably some of you would have an answer on (most likely I just understood something wrong).

So in this example basically we secure an endpoint in vertx with Keycloak as SSO provider and we dont use session handling on vertx side. This way basically each request to a protected source will be verified via SSO, and - as we have no sessions on our side - the user will see in its browser the requested resource content but the url itself is the callback url (so due to the lack of session oauth handler just performs a reroute and not a redirect.

So my questions:

- would it be a valid scenario to use session handling on client side and therefore being able to redirect the user to the resource url he actually asked for AND would having a client session allow us to only redirect to SSO login when the user was never authenticated in our session yet (as eg the expiration is contained in the token - and I also understood that in Keycloak it is possible to configure kind of  session/token expiration calls to the client applications)? Or is that a completely nonsense scenario just imagined by myself? I tried to use session handler but that resulted just in infinite redirection loop. 

- How would it be possible to handle something like hard login required for certain actions? I dont see how we can know if the user in SSO eg did login explicitely (or eg was auto remembered)? 

Would be great to have some input on this even if it might not be a 100% vertx issue. 

Thanks

Roman Pierson

unread,
Aug 23, 2017, 11:34:24 AM8/23/17
to vert.x
Just played around with this a little bit and basically what I did was to 

  • OAuth2AuthHandlerImpl
    • In the callback storing the access token in the session
    • In the route handler setting the access token as user to the context if it is contained in the session
    • Still the token is validated against Keycloak in this case (via introspect)
So this is basically what I had in mind but I am quite unsure if this is a feasible solution from a security perspective or if this is against how this is intended to work?

Paulo Lopes

unread,
Aug 23, 2017, 3:02:40 PM8/23/17
to vert.x

Hi,

I’m not sure if I totally understand your questions so I’ll try to answer anyway.

Keycloak is a SSO solution that uses OpenID Connect which is built on top of OAuth2 (in other words it does more than just OAuth2).

In Oauth2 you usually configure your Keycloak to one of the possible flows:

  • Private
  • Public
  • Bearer only

When you’re developing web applications where the auth happens at the server side (your vert.x code) you should choose “Private”. In this case you’re using the AUTH_CODE flow.

The example you saw was using this and you can either use it without sessions and redirects are required, or you can enable the session handler and your browser will remember you. For this you will need:

router.route().handler(CookieHandler.create());
router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)));
// you can put your auth handler here
router.route().handler(UserSessionHandler.create(authProvider));

Now you’re refering to keep the session client side, by this I think you’re speaking on single page applications. When using this mode you should configure keycloak for the Public flow. and then authenticate using JS skipping all this vert.x setup.

You should refer to this doc: https://keycloak.gitbooks.io/documentation/securing_apps/topics/oidc/javascript-adapter.html

Now everything is handler at the web client side, so on your backend you have 2 choices:

Either configure OAuth2 handler for keycloak or just use the JWTAuthHandler since all you need now is to parse the token the js script got for you.

The important part here is that your js client code when doing AJAX calls should add the correct headers, something like:

var req = new XMLHttpRequest();
// add the required headers
req.setRequestHeader('Accept', 'application/json');
req.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
...

Roman Pierson

unread,
Aug 24, 2017, 7:36:31 AM8/24/17
to vert.x
Hi Paulo

Thanks a lot for the detailed response.

Indeed what I try to achieve is the situation with the UserSessionHandler, not a client in the sense of eg a javascript client. 

Actually I did not know about this UserSessionHandler, and I basically just experimented with implementing this functionality for my workaround directly into the  OAuth2AuthHandlerImpl.

My code would look then something like this (simplified):

OAuth2Auth keyCloakAuthProvider = KeycloakAuth.create(vertx, keycloakJson);


OAuth2AuthHandler oauth2 = OAuth2AuthHandler.create(keyCloakAuthProvider, "http://localhost:8081");


router
.route().handler(CookieHandler.create());
router
.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)));


oauth2
.setupCallback(router.get("/callback"));


router
.route().handler(oauth2);
router
.route().handler(UserSessionHandler.create(keyCloakAuthProvider));


// Here comes the real content....
router
.route("/products")......

I assume thats how it should be done? But when i check the code of the callback handling in OAuth2AuthHandlerImpl to me it looks like that should never work as basically the callback handler terminates the request by sending the redirect and as it does not call the next handler the user will never be written to the session by the UserSessionHandler. Or I am doing something wrong?

Paulo Lopes

unread,
Aug 24, 2017, 8:11:40 AM8/24/17
to vert.x
Hi,

If you want to understand how OAuth2 works and in this specific case (AUTH_CODE flow) see this link: https://aaronparecki.com/oauth-2-simplified/#web-server-apps

2 things happen:

1) a request is made to your application, Oauth2Handler will the verify that there is no user, so it will redirect you to Keycloak
1.1) keycloak will return a html page with login/password form
1.2) on submit (to keycloak) if everything is fine it will redirect again to the callback route (the one you enabled on `setupCallBack`)

2) the callback will then validate the response from keycloak
2.1) if it is valid it will set the user object in your context
2.2) if there is a session store the usersession handler will link it to a session cookie so it is persistent and redirect (to the protected resource)
2.3) if there was no session store it will perform an internal redirect (no state is preserved, so you need to authenticate all the time)

So your observation is 50% correct, the OAuth2 handler will always redirect to keycloak (if there is no session handler), the magic happens on the `callback` route where keycloak responses are validated and transformed to a user object and processing continues.

Roman Pierson

unread,
Sep 30, 2017, 6:39:00 AM9/30/17
to vert.x
Hi

I think at the end I found out what was wrong, from your proposal ....

router.route().handler(CookieHandler.create()); router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx))); // you can put your auth handler here router.route().handler(UserSessionHandler.create(authProvider));

.. I think what I understood wrong was that its important that the auth provider indeed should be created before registering the UserSessionhandler (as its required for this), BUT registering the AuthHandler on the route itself must happen after the UserSessionHandler.....thats why it did not work for me  - however it caused me to look into those handles and what they do so was very useful exercise I guess ;-)

Cheers
Roman

Paulo Lopes

unread,
Oct 1, 2017, 12:58:10 PM10/1/17
to vert.x
Hi,

I’ve created the following tutorial:

http://vertx-tutorials.jetdrone.xyz/tutorials/oauth2/github/

It’s github centric but you can just replace the config with keycloak and the ideas are the same.

Maybe this will make everything easier to understand...
Reply all
Reply to author
Forward
0 new messages