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

What fields should my JWT define? #201

Open
caniko opened this issue Mar 2, 2022 · 12 comments
Open

What fields should my JWT define? #201

caniko opened this issue Mar 2, 2022 · 12 comments

Comments

@caniko
Copy link

caniko commented Mar 2, 2022

First:
I have an authentication server that generates JWTs, and I would like to use it for authentication in StargateAPI. I couldn't find an explicit outline of fields that the JWT needs to store in the docs. What are these fields?

Second:
I am interested in implementing row-based permission for modification, and I would like to avoid creating roles in CQLSH, and do it purely over JWTs. The logical operation is simple: if the owner ID (table column) is not identical to the user ID (on the JWT) the client has no modication rights, but can still read the row. I believe at least some devs to be interested in this topic, it should be mentioned.

The authentication documentation should focus on defining/outlining more key concepts, including these.

@mpenick
Copy link

mpenick commented Mar 14, 2022

It sounds like you might want to implement a custom AuthenticationService (authn) and AuthorizationService (authz).

The token-based auth. service is very simple and can be used as a skeleton for getting started creating a JWT version: https://github.com/stargate/stargate/tree/v1.0.50/auth-table-based-service/src/main/java/io/stargate/auth/table

The JWT could contain whatever you need to handle authn/authz.

@caniko
Copy link
Author

caniko commented Mar 26, 2022

I want to avoid customizing the code... The dream was to just use the K8ssandra helm chars or Kustomize.

@dougwettlaufer
Copy link
Contributor

@caniko have you taken a look at the JWT docs here?

https://stargate.io/docs/stargate/1.0/developers-guide/authnz.html#_jwt_based_authenticationauthorization

Your JWT should contain a stargate_claims claim and in that a field of x-stargate-role which matches the role in the DB. Here's where all that is handled

https://github.com/stargate/stargate/blob/234becf8db63acb9d680828ea22ed57524b861f8/auth-jwt-service/src/main/java/io/stargate/auth/jwt/AuthnJwtService.java#L39

For row level access control you'll want to create another field inside the stargate_claims with x-stargate-COLUMN_NAME where COLUMN_NAME is the name of the column that you want to use for controlling access. The logic for that is in

https://github.com/stargate/stargate/blob/234becf8db63acb9d680828ea22ed57524b861f8/auth-jwt-service/src/main/java/io/stargate/auth/jwt/AuthzJwtService.java#L83

So, as is, the JWT based auth will perform authn without needing cqlsh but if you want to do full authz then you'll need to modify AuthzJwtService. I also believe you'll need to set -D stargate.cql_use_transitional_auth=true so the persistence module doesn't perform authz and instead trusts it's been done farther up the stack (I haven't looked at that particular functionality in awhile so you'll want to double check).

@caniko
Copy link
Author

caniko commented Apr 20, 2022

Thank you @dougwettlaufer. I have a few more questions:

  1. Could you expand on x-stargate-role? Can this role be the admin role? As mentioned earlier read-access on all, but only modify access if the column value matches its counter part in the JWT. I want to avoid making roles for every user.
  2. How do I pass in the public key of my JWT to Stargate for it to be decrypted? Can I give a K8 secret URL and key?

Also, I don't think I need custom authz on the Stargate side.

@dougwettlaufer
Copy link
Contributor

  1. Could you expand on x-stargate-role? Can this role be the admin role? As mentioned earlier read-access on all, but only modify access if the column value matches its counter part in the JWT. I want to avoid making roles for every user.

The x-stargate-role is the role you've created via cqlsh. So if you've created web-user and web-user-admin roles then in your IDP you'll map which users get which role set in the x-stargate-role claim.

  1. How do I pass in the public key of my JWT to Stargate for it to be decrypted? Can I give a K8 secret URL and key?

You'll pass the URL of the "well-known" endpoint to stargate with -Dstargate.auth.jwt_provider_url

@caniko
Copy link
Author

caniko commented Apr 25, 2022

The x-stargate-role is the role you've created via cqlsh. So if you've created web-user and web-user-admin roles then in your IDP you'll map which users get which role set in the x-stargate-role claim.

This makes sense, thank you.

You'll pass the URL of the "well-known" endpoint to stargate with -Dstargate.auth.jwt_provider_url

Using JWKS is OK. However, I was hoping to have the option to decrypt the JWT on Stargate by passing the public key from an opaque secret.

@caniko caniko closed this as completed Apr 25, 2022
@caniko caniko reopened this Apr 25, 2022
@caniko
Copy link
Author

caniko commented Apr 25, 2022

@dougwettlaufer, could you confirm if the example below is correct?

-D stargate.cql_use_transitional_auth=true

Read scenario
The JWT has stargate_claims with a cqlsh_role that has read access -> Stargate returns the queried rows.

Modify scenario
The JWT has stargate_claims:

{
  `x-stargate-COLUMN_NAME`: <correct value>
  `x-stargate-role`: `cqlsh role`
}

Stargate relays the modification requested by the client to Cassandra.

@dougwettlaufer
Copy link
Contributor

@caniko that should be correct. Although you can probably leave off stargate.cql_use_transitional_auth

@caniko
Copy link
Author

caniko commented Apr 27, 2022

@dougwettlaufer

Lastly, which of the key-value pairs returned from the JWKS endpoint is used by Stargate?
JWKS:

{
    "keys": [
        {
            "kid": "vdaec4Br3ZnRFtZN-pimK9v1eGd3gL2MHu8rQ6M5SiE",
            "kty": "RSA",
            "alg": "RS256",
            "use": "sig",
            "n": "4OPCc_LDhU6ADQj7cEgRei4VUf4PZH8GYsxsR6RSdeKmDvZ48hCSEFiEgfc3FIfh-gC4r9PtKucc_nkRofrAKR4qL8KNNoSuzQAOC92Yz6r7Ao4HppHJ8-QVdo5H-d9wfNSlDLBSo5My4b4EnHb1HLuFxDqyhFpGvsoUJdgbt3m_Q3WAVb2yrM83S6HX__vrQvqUk2e7z5RNrI7LSsW3ZOz9fU7pvm8-kFFAIPJ7fOJIC7UQ9wBWg3YdwQ0B2b24jXjVr0QCGzqJ6o1G_UZYSJCDMGQDpDcEuYnvSKBLfVR-0EcAjolRhcSPjHlW0Cp0YU8qwWDHpjkbrMrFmxlO4Q",
            "e": "AQAB"
        }
    ]
}

kid means key id, alg is the algorithm, and n is the public key used for this realm. Example copied from redhat article for keycloak.

Definitely alg and n. Any of the other ones?

And, how does Stargate know which kid to use for the JWT? Is the kid in the JWT?

@polandll
Copy link
Contributor

polandll commented Jun 7, 2022

@caniko - Did you ever get further with this project? Is there anything that you believe should be documented from your experience with JWT?

@caniko
Copy link
Author

caniko commented Jun 7, 2022

@polandll I am currently blocked by #558 on the k8ssandra side for proper testing.

Please answer the questions from my last post in the meantime.

@caniko
Copy link
Author

caniko commented Jul 13, 2022

@dougwettlaufer additional to my previous question: What if correct value has no match in the COLUMN?

{
  `x-stargate-COLUMN_NAME`: <correct value>
  `x-stargate-role`: `cqlsh role`
}

Is it only read in that case? Or can I provide another role in those cases?

As mentioned before: I want global read-only.

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

4 participants