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

Change call/response JMX auth header #242

Merged
merged 4 commits into from
Aug 19, 2020

Conversation

andrewazores
Copy link
Member

@andrewazores andrewazores commented Aug 18, 2020

Related to #5

Server's "call" is changed to X-JMX-Authenticate, while corresponding
client response is left as "X-JMX-Authorization". This matches the HTTP
WWW-Authenticate/Authorization headers.

This header will be used by clients to discover the authentication scheme expected by the ContainerJFR instance. The only supported scheme at this time is Basic.

Server's "call" is changed to X-JMX-Authenticate, while corresponding
client response is left as "X-JMX-Authorization". This matches the HTTP
WWW-Authenticate/Authorization headers.
Use consistent status code to indicate to client similar failures, allowing interactive clients to easily detect various cases of authentication failure
@andrewazores andrewazores force-pushed the jmx-auth-call-response branch from 310fe44 to 14aa38b Compare August 18, 2020 19:22
@vic-ma
Copy link
Contributor

vic-ma commented Aug 19, 2020

I'm trying to figure out how to test this and how the auth stuff works in general.

Is JMX authentication always enabled, or is that what the flag Dcom.sun.management.jmxremote.authenticate does? Though I think that flag existed before all the JMX auth PRs, so maybe not?

How does JMX auth relate to user authentication? When you say:

The only supported scheme at this time is Basic

Is this referring to the BasicAuthManager, and so I should enable that when testing this, or do you mean something else?

@andrewazores
Copy link
Member Author

andrewazores commented Aug 19, 2020

JMX authentication will be enabled whenever CONTAINER_JFR_RJMX_AUTH=true, CONTAINER_JFR_RJMX_USER=something, or CONTAINER_JFR_RJMX_PASS=something. When any of those are true/set, then the flag -Dcom.sun.management.jmxremote.authenticate=true is set and so are -Dcom.sun.management.jmxremote.password.file=$PWFILE and -Dcom.sun.management.jmxremote.access.file=$USRFILE, which are what tell the JVM what users have which roles and what their passwords are for securing its own JMX listening port. These are all standard JVM flags, not ContainerJFR specific.

JMX auth is for users to authenticate themselves to targets which are configured using the JVM flags described above. User auth, using the BasicAuthManager for example, is for users to authenticate themselves to ContainerJFR itself. User auth ensures that the user has access to ContainerJFR in general, and JMX auth ensures that users have access to specific targets.

"The only supported scheme at this time is Basic" refers to the way that credentials are provided in the authorization header - Basic is a scheme meaning that the credentials are provided like base64(username:password). This is also a standardized auth scheme, not specific to ContainerJFR or either the connection between ContainerJFR/target or client/ContainerJFR. Another common scheme is Bearer, using Bearer tokens, which we have an example of in the OpenShiftAuthManager for example, where rather than sending their username:password directly to the server, clients instead have some kind of authorization token that has been provided to them by the server and which they pass back with requests to prove their identity. Here's a link to get you started on auth schemes: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate

More specifically here this refers to the method AbstractAuthenticatedRequestHandler#getConnectionDescriptorFromContext. When the handler sets the header key X-JMX-Authenticate it uses the value Basic to advertise to clients that the expected auth scheme is Basic. When the same method sees an X-JMX-Authorization header it takes the value and assumes that it is in the base64(username:password) format and attempts to process it as such. If anything is wrong it fails the request (and re-advertises the expected scheme). If it succeeds then it uses the provided credentials to create the ConnectionDescriptor, which will later be used by the TargetConnectionManager when establishing the JMX connection to the target.

To test it, you can use the web-client on my jmx-auth branch (for which a PR is still open awaiting this one), or you can use curl.
For example:

CONTAINER_JFR_RJMX_USER=user CONTAINER_JFR_RJMX_PASS=pass sh run.sh
curl -v -X POST --data "recordingName=foo&duration=30&events=template=Profiling" -H "X-JMX-Authorization: Basic $(echo -n user:pass | base64)" localhost:8181/api/v1/targets/localhost/recordings
curl -v localhost:8181/api/v1/targets/localhost/recordings/foo --output foo.jfr # try a request without JMX auth
curl -v -H "X-JMX-Authorization: Basic $(echo -n user:pass | base64)" localhost:8181/api/v1/targets/localhost/recordings/foo --output foo.jfr # try a request with JMX auth

@vic-ma
Copy link
Contributor

vic-ma commented Aug 19, 2020

It's working as intended with curl (just had to change .../recordings/foo to .../recordings).

The code looks good as well, but it just needs a spotless:apply.

@andrewazores
Copy link
Member Author

andrewazores commented Aug 19, 2020

It should work with .../recordings/foo too, although I suppose it will try to download the JFR binary and dump that to stdout, so curl will probably complain. Append a --output foo.jfr to the second and third curl commands and it should continue normally and download the file. The first POST request can also be tested without the added header, or with incorrect/malformed credentials, to exercise it more thoroughly and see that fail. In fact, any HTTP API under the path /api/v1/targets/:targetId/* should fail without correct credentials provided.

@vic-ma
Copy link
Contributor

vic-ma commented Aug 19, 2020

Oh, I thought that command was just to see what recordings were in localhost (like running list), and I didn't see the usual output so I changed it...I'll try again now.

@vic-ma
Copy link
Contributor

vic-ma commented Aug 19, 2020

Yeah, it works with --output foo.jfr appended.

@andrewazores andrewazores merged commit ae17f9f into cryostatio:main Aug 19, 2020
@andrewazores andrewazores deleted the jmx-auth-call-response branch August 19, 2020 20:19
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

Successfully merging this pull request may close these issues.

2 participants