-
Notifications
You must be signed in to change notification settings - Fork 31
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
OAuth Redirect Authentication flow #717
Comments
After doing some research, I have a few questions about whether I’m approaching this issue correctly. Which grant type applies to our case? The docs mention the “client” asks the OAuth server for access to the “protected resource”. I’m assuming the resource is the user’s Bearer token. Who is the “client” in this case? The web client or the cryostat backend? Lastly, am I understanding this authorization flow correctly?
|
From that description the "Implicit Flow" seems to match best - from the OAuth server's perspective, the requesting client is the cryostat-web instance running in a user's browser, and not the cryostat backend. The backend is just acting as a proxy. The "protected resource" would not be the user's general access token, I don't think. It is most likely that the resource referred to is a specific API resource, similar to what I am doing in #718, where a resource would be a recording .jfr file, or a report .html file. In the example given, the "resource" according to the Google OAuth server could be "the user's gmail account". It may be possible to consider the OpenShift API as a whole to be "resource", but I think this is more likely to be something we would have to specify with the Your authorization flow steps are basically correct, if you consider that the "client" is the user interacting via the web-client. The Cryostat backend should be essentially transparent in the auth flow since it is only acting as a proxy, and won't be storing the user's authorization code or access token at any point. When the web-client connects to Cryostat and does the initial This will cause the browser to redirect to the OAuth server, perform their auth if needed (they may still have an active session with the OAuth server in which case the login is skipped and the existing session used), and then the browser will receive another 302 response from OAuth. This time, the Now that the web-client has been reloaded, it should check for the My only outstanding question here is whether the |
Now that I have thought it through some more and written all this down, I don't really think we need to use vertx's oauth client library that I linked. That would be useful if Cryostat were running as a server-side application and creating user sessions, holding state, and storing the user's authorization code. Since we are just treating Cryostat as an authorization server proxy and doing all of the session and state stuff on the user's browser, we don't have any need for the server-side OAuth client. |
That makes sense, especially since we already have RBAC support. Should we close this issue? |
I think the issue can remain open - there is still some work to do on the AuthPostHandler so that it can send the proper redirect to the client. This should obviously only happen when the AuthManager is one where that makes sense (ie OpenShiftAuthManager), so there will also need to be some work done on the AuthManager and its implementations to sort out how to handle that redirect flow. |
I think the
Manually entering After logging in, clicking “Display Token” shows a new Bearer token. This token has a different hash than the one I get from To discover the token request URL programmatically, it looks like I might be able to write a GET request to https://openshift.default.svc/.well-known/oauth-authorization-server from within Cryostat. The |
After hardcoding a 302 response with Location header with the URL I have two questions:
Screencast.from.2021-10-28.05.35.38.PM.mp4 |
Reading https://www.oauth.com/oauth2-servers/client-registration/client-id-secret/ : From what I understand, the purpose of the The actual implementation on the Cryostat side might never need to make a direct request to The The demo screencast looks awesome. A slow connection - in particular one with long latencies - will always suffer from this kind of SSO redirect login flow, and there isn't a whole lot we can do about it other than making sure we don't make any requests to load unnecessary resources etc. before redirecting the user away to the OAuth login. One thing we could do to smooth out the experience slightly would be to get rid of the visible Bearer auth login form. We currently need that so the user can enter their token manually, but if the token is received by an OAuth redirect then the login "form" implementation could be similar to the Noop one where it displays nothing and allows the user in as soon as it reads the token from the URL and stores that in the LoginService. (I'm not sure how we would want to differentiate between Bearer auth where the user manually supplies the token and Bearer auth where the web-client receives the token via OAuth redirect - maybe we need something other than the Authorization authMethod here) |
Here's what I've found about the The OpenShift docs here mention that service accounts acting as OAuth clients have a reduced set of scopes, meaning it can't request a Instead of specifying Any ideas about how we could reuse the existing RBAC permissions to request a token with full access to the API?
|
The operator's I don't know if the
When/where does this occur? Is this in the browser after you try to log in graphically, or is this happening at some time when Cryostat is trying to make an OAuth API request using its own service account token? What is the interaction between OAuthClient and serviceaccount? In my mind the overall model I have is that the OAuthClient resource just represented the web-client/its redirect URI/the user interacting through it, so when the user is going through the redirect login flow they are communicating directly to the OAuth server and not through a service account. They provide their credentials and the server sends them back their OAuth token for whatever scope is required. Separately, Cryostat has its own service account and token, which it can use to communicate with the same OAuthServer as its own form of limited OAuthClient, and at times it does these communications while masquerading as the user after the user has supplied their token along with some attempt to perform an authenticated action. But at the initial login stage where the user is acquiring their token from the OAuth server the Cryostat service account hasn't been involved yet, right? |
After I login from the OpenShift Container Platform login page, the OAuth server returns the redirect URI with an error description instead of a token:
Based on the description from the Implicit Grant Flow rfc, I think the “client” is our service account, “user-agent” is the web browser, “authorization server” is the OpenShift OAuth server, “resource owner” is a human user that knows their When the Visiting Visiting |
I realized that the |
Thanks, this all makes sense and your interpretation of
Sounds good - that would explain why setting the If there are no existing cluster roles that meet our needs then I think we can discuss with @ebaron about adding a new |
I'm a bit confused about the role scope. This is so we get a token that has the permissions needed by the permissions API, right? If I remember correctly, the token the user enters manually is only used to do a TokenReview and SelfSubjectAccessReview. In that case, would we be able to get away with just using the |
Here's what I know: https://github.com/cryostatio/cryostat/blob/d486871f35479b18c1a44360fe4e18697bee58ff/src/main/java/io/cryostat/net/OpenShiftAuthManager.java#L270
I'm not sure which exact permissions the backend needs to complete all of the web-UI actions. I essentially started with an empty
|
This is something we should probably make easier to determine. The permissions required for each action are defined by the API handlers themselves: That set of https://github.com/cryostatio/cryostat/blob/d486871f35479b18c1a44360fe4e18697bee58ff/src/main/java/io/cryostat/net/OpenShiftAuthManager.java#L166 (the two We could generate a manifest of the required Cryostat application-level permissions easily enough by ex. implementing a new From there, if we hoist those |
Thanks for the explanation Janelle! The OpenShift documentation about the scopes could be a bit more precise. FWIW, I seem to have found the code where the scopes are translated into RBAC objects, so we can see exactly what permissions they give: https://github.com/openshift/apiserver-library-go/blob/5cdb70a1e65b6bcabb3b897e38287ed2c8ed77d1/pkg/authorization/scope/converter.go It looks like the Interestingly |
I made a handler on jan-law:list-permissions that outputs this list of permissions: https://gist.github.com/jan-law/8bedb15a7027d2697191ea8b01dfd856 Some of the How do the rest of the |
They don't necessarily - not everything that I defined as a resource from Cryostat's POV has been mapped to something in OpenShift RBAC. Not yet, anyway, and for some of them maybe not ever. There is no CRD for managing Credentials, for example, and so there's no RBAC mapping there.
TokenReviews and SelfSubjectAccessReviews are OpenShift-specific auth implementation details, so they don't show up in Cryostat's application-level model of resources/actions since we need that to be more generic - it needs to also be applicable to the
That's what I was talking about in my previous blurb here:
Pulling out that resource type/action mapping functionality from an OpenShiftAuthManager internal detail into something common to all AuthManagers might be worthwhile, but just for your purposes in your feature branch |
Looks good! If you cross-reference that output with the mapping here, you'll have a complete list: https://github.com/cryostatio/cryostat/blob/05955511d9b5147ad93a5f844d6e408db68dbe98/src/main/java/io/cryostat/net/OpenShiftAuthManager.java#L312-L345 It should be some subset of CRUD on:
|
Thanks! Here's the output:
When I ran Cryostat on OpenShift with the same clusterRole permissions as above, with the role scope set to
|
Ah, the first two are probably from the discovery/tree API. It's capable of making the following
I'm not sure where the |
The |
As of now, access tokens expire in 24 hours, which means if you click "Logout", any backend queries to the OAuth server will return the existing token instead of redirecting to the OpenShift Container Platform login page. Would you prefer if I made a separate PR to add a logout capability or add it to #748 ? |
It might be easier to review as a separate follow-up PR. |
I think once this is finished, we should verify the complete workflow with both kubeadmin and regular users. There seems to be at least some difference in how authentication works between them: |
https://vertx.io/docs/vertx-auth-oauth2/java/
Vert.x supports OAuth redirect authentication flow. Cryostat could support this when using the OpenShiftAuthManager, or any other AuthManager implementation that delegates to an OAuth server. This way the user would not supply their Bearer token directly to Cryostat. Instead, the user would visit the Cryostat web-client and be redirected to the platform OAuth server, allowing the user to log in with whatever credentials that server is configured to require (OpenShift cluster username/password, LDAP, or some other SSO). After successful authentication the user would be redirected back to the web-client with their access token as a query parameter, which the web-client should be able to capture and store as usual.
The text was updated successfully, but these errors were encountered: