Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KeyCloak jwt support #73

Closed
paulbakker opened this issue Jul 3, 2016 · 3 comments
Closed

KeyCloak jwt support #73

paulbakker opened this issue Jul 3, 2016 · 3 comments

Comments

@paulbakker
Copy link
Contributor

paulbakker commented Jul 3, 2016

Scenario: A JavaScript UI that uses the KeyCloak redirect flow, and a Vert.x REST backend. The UI authenticates with the redirect and gets a token from KeyCloak. The token is added to each request to the Vert.x backend.

The KeyCloak token is, according the KeyCloak docs, "an extension of JWT". The token is self contained, meaning that user info such as the user's roles are embedded in the token. To check authorization for a specific action on the Vert.x backend, the backend would have to verify the token (using the public key), and read the roles from the token. No communication with KeyCloak is required.

Problem: The oauth2 module for Vert.x supports KeyCloak, but only the redirect flow. This is not useful in the scenario where Vert.x is only used for serving the backend. The jwt module sort of does the right thing, but doesn't seem to support KeyCloak token. This has to do with the specific format of the token, but I'm not sure about the details of this problem.

This should be supported out of the box. I did create a workaround, but this relies on an implementation class from the oauth2 module. Alternatively one of the available 3rd party JWT libraries could be used, but support in Vert.x would be a lot easier.
The following is an example of the code that I'm currently using for auth, based on the TokenVerifier, which is an implementation class.

import io.vertx.ext.auth.oauth2.impl.crypto.TokenVerifier;

public void handle(RoutingContext req) {
        String authHeader = req.request().getHeader("Authorization");
        if(authHeader != null) {
            String jwt = authHeader.substring(authHeader.indexOf(" ") + 1);
            TokenVerifier tokenVerifier = new TokenVerifier(m_config.keycloakPublicKey);
            JsonObject verify = tokenVerifier.verify(jwt);
            req.setUser(new User(new WebUser(verify)));

            req.next();
        } else {
            req.response().setStatusCode(403).end();
        }
    }

The WebUser type is just a wrapper.

public class WebUser implements User{

    private final JsonObject m_principal;

    public WebUser(JsonObject principal) {
        this.m_principal = principal;
    }

    @Override
    public User isAuthorised(String authority, Handler<AsyncResult<Boolean>> resultHandler) {
        return this;
    }

    @Override
    public User clearCache() {
        return this;
    }

    @Override
    public JsonObject principal() {
        return m_principal;
    }

    @Override
    public void setAuthProvider(AuthProvider authProvider) {
    }
}

Once we decide on the correct solution I would be happy to work on a PR.

@pmlopes
Copy link
Contributor

pmlopes commented Jul 4, 2016

The current JWT impl can handle the KeyCloak tokens if you use it like:

JsonObject config = new JsonObject().put("public-key", "BASE64-ENCODED-PUBLIC_KEY");
AuthProvider provider = JWTAuth.create(vertx, config);

The main problem now is to tell the JWT where to look for the roles. In the default implementation if looks for a json object hash, while on KeyCloak the token has a top level set of hashes:

  • realm_access

  • resource_access

    and inside these then there are the roles.

Once way to "fix" could be where this is used:

https://github.com/vert-x3/vertx-auth/blob/master/vertx-auth-jwt/src/main/java/io/vertx/ext/auth/jwt/JWTOptions.java#L190

Then instead of assuming a direct key parse it as a path, say:

access_token/realm_access/roles

However this would give you the basic roles it does not do the extra KeyCloak specific validations such as realm name.

@paulbakker
Copy link
Contributor Author

Took a while to get back to this issue (holidays), but I just created a PR.

pmlopes added a commit that referenced this issue Aug 29, 2016
#73 Added support for roles in nested object structure
@paulbakker
Copy link
Contributor Author

I guess this issue can be closed now after the merge?

@pmlopes pmlopes closed this as completed Sep 14, 2016
@pmlopes pmlopes removed the wishlist label Sep 14, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants