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

Add JWT bearer authorization #1149

Open
wants to merge 1 commit into
base: master
from

Conversation

@kthomas
Copy link

kthomas commented Oct 3, 2019

This effort adds the ability for a third-party to sign JWT tokens containing well-formed permissions within the payload and run NATS server configured with the public key for signature verification.

The initial version of this PR represents the result of a quick and dirty spike to get something that could be tested against a fast-moving project in the blockchain space. It makes sense to consider this functionality because it allows applications to leverage the existing NATS permissions model without the need for an account server. This is an alternative strategy to nkey auth.

When "bearer authorization mode" is configured, a connection to NATS will fail to be authorized under the following conditions:

  • when no bearer token is provided by the client
  • when a bearer token is provided but fails signature verification based on the configured JWT_SIGNER_PUBLIC_KEY
  • when the bearer token is verified but no permissions claim exists in the JWT

The authorization model under this strategy is delegated to NATS by the application, and JWT tokens which an application vends need to be issued with a short ttl; applications and NATS clients need to consider the refresh cycle. I am considering how to best support an interface for defining a configurable callback within NATS clients which will ask the application to vend a new token (i.e. "refresh" the soon-to-expire token) at the appropriate time and gracefully recycle the socket to establish a new NATS connection using the newly-authorized token, just prior to the previously-valid token exp timestamp.

There are some obvious things that need to be resolved in the course of diligence here that I am working on:

  • removing the hack of adding a third-party JWT package directly instead of updating the NATS JWT package
  • supporting NATS streaming [and JetStream] (to be addressed in separate PR)
  • providing broad client support for gracefully refreshing bearer tokens just before they expire as described above (to be addressed in separate PRs)

If you want to run the branch to try it out, you can check it out, go build and then run the following:

➜  nats-server git:(jwt-bearer-auth) JWT_SIGNER_PUBLIC_KEY='
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqU/GXp8MqmugQyRk5FUF
BvlJt1/h7L3Crzlzejz/OxriZdq/lBNQW9S1kzGc7qjXprZ1Kg3zP6irr6wmvP0W
YBGltWs2cWUAmxh0PSxuKdT/OyL9w+rjKLh4yo3ex6DX3Ij0iP01Ej2POe5WrPDS
8j6LT0s4HZ1FprL5h7RUQWV3cO4pF+1kl6HlBpNzEQzocW9ig4DNdSeUENARHWoC
ixE1gFYo9RXm7acqgqCk3ihdJRIbO4e/m1aZq2mvAFK+yHTIWBL0p5PF0Fe8zcWd
NeEATYB+eRdNJ3jjS8447YrcbQcBQmhFjk8hbCnc3Rv3HvAapk8xDFhImdVF1ffD
FwIDAQAB
-----END PUBLIC KEY-----' ./nats-server -DV
  • Link to issue: related to #434
  • Documentation added (in progress)
  • Tests added
  • Changes squashed to a single commit (described here)
  • Build is green in Travis CI
  • You have certified that the contribution is your original work and that you license the work to the project under the Apache 2 license

/cc @nats-io/core

@kthomas kthomas referenced this pull request Oct 3, 2019
@derekcollison

This comment has been minimized.

Copy link
Member

derekcollison commented Oct 7, 2019

Will take a look today, thanks for the patience.

@kthomas

This comment has been minimized.

Copy link
Author

kthomas commented Oct 7, 2019

No rush. I still need to add some tests etc.

@kozlovic

This comment has been minimized.

Copy link
Member

kozlovic commented Oct 7, 2019

@kthomas I had a look, but this is early stage WIP, so no much to comment on. I would pass the server or logger to the BearerAuthFactory() function so that you can then use the logger instead of fmt.Println() calls.

@kthomas

This comment has been minimized.

Copy link
Author

kthomas commented Oct 7, 2019

Thanks @kozlovic -- I had begun poking around looking for how to best use the package logger. Makes sense to pass it along.

I will be pushing another commit or two shortly to clean things up, including tests, and we can discuss.

@wuhenfeike

This comment has been minimized.

Copy link

wuhenfeike commented Oct 9, 2019

I see that the current sub and push limit are set when the client login, can it be changed to set the sub and push permission at any time?

@wuhenfeike

This comment has been minimized.

Copy link

wuhenfeike commented Oct 9, 2019

@kthomas Or when subscribing or pushing to the server, the server can query the user's push and subscription rights from mysql or other databases to restrict the push and subscription rights。

@kthomas

This comment has been minimized.

Copy link
Author

kthomas commented Oct 9, 2019

@wuhenfeike if I understand your question correctly, it sounds like it could be supplied within your bearer token similarly to how permissions is being presented. You could issue a new token to update it I presume.

That is out of scope for the PR as of this moment but I will take a look to see how it could be supported as I groom this further. It seems you could present those limits as part of the signed token payload as well.

I didn't follow the question related to re-centralizing on a SQL database, you lost me there.

@wuhenfeike

This comment has been minimized.

Copy link

wuhenfeike commented Oct 10, 2019

Thanks @kthomas For example, in iot scenario application, two clients can know the restricted objects of push and subscription after determining the binding relationship, so whether can provide the function of dynamically setting push and subscription limits.

@kthomas kthomas force-pushed the kthomas:jwt-bearer-auth branch from fe73145 to 06dcbda Oct 12, 2019
@kozlovic

This comment has been minimized.

Copy link
Member

kozlovic commented Oct 14, 2019

@kthomas Just a note: although we have go.mod, as of now, we build/test from vendor directory. So you would have to go mod vendor and add the jwt into vendor in the commit if you want Travis to run the tests...

@kthomas

This comment has been minimized.

Copy link
Author

kthomas commented Oct 14, 2019

Have some tests to commit as well @kozlovic -- ty for this.

@kthomas kthomas force-pushed the kthomas:jwt-bearer-auth branch 10 times, most recently from 96e58b5 to aab67f6 Oct 15, 2019
Uses RS256 signature verification
@kthomas kthomas force-pushed the kthomas:jwt-bearer-auth branch from aab67f6 to eae9471 Oct 16, 2019
@kthomas kthomas changed the title [WIP] Add JWT bearer authorization Add JWT bearer authorization Oct 16, 2019
@kthomas

This comment has been minimized.

Copy link
Author

kthomas commented Oct 16, 2019

@derekcollison @kozlovic this is probably ready for another pass when you have a chance.

@hastarin

This comment has been minimized.

Copy link

hastarin commented Oct 21, 2019

Excuse my ignorance but is this something that could tie in with an external service like auth0.com to better fit NATS server into a OIDC/OAuth 2.0 flow?

@kthomas

This comment has been minimized.

Copy link
Author

kthomas commented Oct 21, 2019

@hastarin this is meant to be very primitive for portability's sake.

The intent of this PR is indeed to allow third-party services to generate and sign JWT credentials (in essence delegating the NATS authorization to some service without having to run extra NATS account server infrastructure). So if the third-party service supports generating JWT tokens with arbitrary claims and signing them using the RS256 algo, then such a service would indeed be supported.

Hope this answers your question.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.