metrumresearchgroup / focal

Authenticated reverse proxy based on PAM Authentication
MIT License
1 stars 0 forks source link

invalid/expired token implementation #2

Open dpastoor opened 4 years ago

dpastoor commented 4 years ago

I'm not sure if that was the exact problem, but after leaving up the grafana dashboard overnight, it came back with a bunch of errors, as I'm pretty sure the token had expired. A full refresh at the root re-prompted to login and was back in business.

Should consider the scenario of log-lived connections and how refresh/re-auth will be handled.

shairozan commented 4 years ago

Yeah so that's probably because of all the AJAX work in the background. All the background threads are trying to make the requests and getting 401 unauthorized, but they're not written to redirect the foreground, rather just throw the errors. If you do it again and just refresh the page, which would be a new request, it should have forwarded you back to the login.

I'll verify that logic though. We may need to look at allowing people to set expiration values by environment variable as well if we want to consider lengthy token validity.

shairozan commented 4 years ago

https://grafana.com/docs/auth/auth-proxy/

Something to look at. We may have to find a way to conform to what it's looking for.

shairozan commented 4 years ago

Well, the auth-proxy doesn't really support raw JWT authentication. It's been an open issue for...a while. https://github.com/grafana/grafana/issues/8198

shairozan commented 4 years ago

I may try the generic oauth and see if I can bypass a lot of the components, or even build a faked UI component for it to redirect back.

dpastoor commented 4 years ago

yep looks like standard header auth

# Defaults to false, but set to true to enable this feature
enabled = true
# HTTP Header name that will contain the username or email
header_name = X-WEBAUTH-USER
# HTTP Header property, defaults to `username` but can also be `email`
header_property = username
# Set to `true` to enable auto sign up of users who do not exist in Grafana DB. Defaults to `true`.
auto_sign_up = true

Similarly rstudio connect does virtually the same thing:

https://docs.rstudio.com/connect/admin/authentication.html#authentication-proxy

IMO, the way we can do this is focal handles the jwt auth, takes the username (or anything else needed) from the token and creates the header, overwriting it if it exists otherwise.

We could use a custom header like X-metworxuser-auth and set that as the token name in all the apps

shairozan commented 4 years ago

Yeah creating the header value would be easy enough at this point. We have separate paths to process UI vs non UI requests, so I can try adding it in there. Was literally looking into the section of "How to make apache auth work" when you commented

dpastoor commented 4 years ago

IMO there should be no difference in the UI vs non-UI - just is authenticated or not. If a programmatic request comes in, it would just get a redirect/unauthorized result and complete right?

I'd like to provide something along the lines of how github provides a access token, where we could do something like:

provide another /token endpoint that provides a login screen, with the username/password. After logging in they can create new tokens and set an optional expiration field that defaults to a much longer timeframe that they can copy and use. Similarly they can see a list of actively provisioned tokens and revoke them. I know this would now mean we'd need to maintain that and also compare to the blacklist, but would be a consistent way to generate tokens.

I'd also want to think about how we could provide a CLI/configuration way of doing so, in the case you don't want to go through the UI, perhaps just hitting the endpoint with the username/password/expiration_date fields

something like

focal token --username=devinp --password=mysecretpasswd

or

curl -u devinp:mysecretepasswd http://example.com/protected/token
shairozan commented 4 years ago

That's doable, but will be a lot of work. We'll have to scrap the JWT middleware's that were built in, and build custom ones. We'll want to probably at least spend some time fleshing the idea out and maybe storyboard some potential pathways.

shairozan commented 4 years ago

Generating the Tokens

Since these are not cryptographically generated, but rather trusted by process, we will generate a guid, base64 encode it, and that will be the token itself

Screen Shot 2019-10-31 at 10 36 16 AM

Managing the Tokens

While there are a lot of go packages dealing with tokens, they all either deal with OAuth or JWT tokens respectively. This is more than likely due to the fact that what we’re looking at doing is manual authorization assignment and is not that programmatically burdensome

Screen Shot 2019-10-31 at 10 36 31 AM

What makes sense is to just keep an in memory map of users to authenticated users to structs containing their tokens. That struct would contain:

Authentication will only really care about active tokens, but we’ll still have the others for reference, or even for custom messages to the user:

“Your authentication token has been revoked. Please reach out to your administrator” “Your authentication token has expired. Please reach out to your administrator”

Persistence

Without persistence, this whole process is kind of pointless, as a restart kills all your tokens, and thus authentication. Without the need to implement crazy 3rd party dependencies, it would be easy to serialize the entire token manager down and write it to a file, with a few caveats.

When doing this, we would want to make sure that the token text fields are AES 256 encrypted at the minimum. This will also incur a cost on startup when the file is read to decrypt everything, but it makes sure that being able to access the file doesn’t give you access to the system.

Command Line Generation

Basing off of a file also gives you the ability to change up how focal runs in general. You could move it to a cobra command where you have a few main targets:

Middleware

We would have to write a new middleware that would do the following:

Management UI

This structure provides a need beyond simple CLI modifications for managing tokens. This should include:

Protecting the Management UI

It would make sense to use the JWT middleware and authentication we have now for focal and apply it only to the management UI. This ensures: