-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Unable to change unauthenticated response with quarkus-resteasy-reactive
#25732
Comments
/cc @FroMage, @geoand, @stuartwdouglas |
Attached example: https://github.com/ivansenic/quarkus-25732 |
@ivansenic Thanks, the mapper is tested here, https://github.com/quarkusio/quarkus/blob/main/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/AuthenticationCompletionExceptionMapper.java, https://github.com/quarkusio/quarkus/blob/main/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java#L696. That test, though quite complex, only passes because the test mapper adds a |
I'll have a look tomorrow |
Thanks @geoand, I did not mean to say it was just a |
Completely understood 😀 |
Hmm but I am not registering a mapper for |
I just tried your sample and handling the exception with the @sberyozkin I think this is best handled by you, since I am lacking a lot of the security context. |
@geoand Thanks. I see that I don't have tests for mapping Perhaps intercepting |
From what I saw from the security code, that does seem to be the case. |
Just checked and intercepting the |
@ivansenic |
@sberyozkin is there anything else we can do to improve here? |
@geoand I'll be on PTO next week, overflowing into the week which follows and looking at some other open issues right now, but yeah, definitely a few things have to be clarified. One thing that is certain is that it is impossible to intercept security exceptions with JAX-RS mappers if the proactive authentication is enabled which is a default - the security chain will start before the JAX-RS chain. 2 other possible options:
|
Thanks a lot @sberyozkin! |
@sberyozkin In turns our that I am already implementing a custom Btw, the header based authentication could be interesting also for contributing back to Quarkus.. Here is a quick showcase on what I did: https://github.com/stargate/stargate/blob/v2.0.0/sgv2-docsapi/src/main/java/io/stargate/sgv2/docsapi/api/common/security/HeaderBasedAuthenticationMechanism.java |
Yup hooking into challenge works.. Just in case that somebody needs it, here is the reference on how I am setting the custom response: https://github.com/stargate/stargate/blob/304cff3ace476737ab1309a44a20b26bed8a7ad7/sgv2-docsapi/src/main/java/io/stargate/sgv2/docsapi/api/common/security/HeaderBasedAuthenticationMechanism.java#L88-L125 As far as I am concerned, the issue is resolved. Thanks @geoand @sberyozkin |
Thanks for the update @ivansenic . I'll leave this open because at the very least, we could use a doc update. |
@ivansenic Nice one, thanks for quickly verifying the custom mechanism option. |
Will look further into it asap, I haven't forgotten |
@michalvavrik Hi Michal, did your PR fix this issue as well ? See also #26314 |
@sberyozkin It's actually very much related to the other tickets I work on, let me have a look. It would be nice to have a solution that covers all related cases, not just this reproducer (and it would fix proactive auth stuff too) |
fixes: quarkusio#25732, quarkusio#22971, quarkusio#26314 (for proactive=false)
fixes: quarkusio#25732, quarkusio#22971, quarkusio#26314 (for proactive=false)
fixes: quarkusio#25732, quarkusio#22971, quarkusio#26314 (for proactive=false)
fixes: quarkusio#25732, quarkusio#22971, quarkusio#26314 (for proactive=false)
fixes: quarkusio#25732, quarkusio#22971, quarkusio#26314 (for proactive=false)
fixes: quarkusio#25732, quarkusio#22971, quarkusio#26314 (for proactive=false)
fixes: quarkusio#25732, quarkusio#22971, quarkusio#26314 (for proactive=false)
fixes: quarkusio#25732, quarkusio#22971, quarkusio#26314 (for proactive=false)
https://issues.redhat.com/browse/SWATCH-849 I had to move `openapi.yaml` to `src/main/resources/META-INF` so that it would be picked up by `OpenApiDocumentService`, so that API definitions could be easily referenced from unit tests (e.g. see `ResourceRolesAllowedTest`). This also makes http://localhost:8000/q/openapi serve more complete API including security schemes. Three roles are defined: - `service` - granted to `x-rh-swatch-psk` authenticated principals - `support` - granted to `x-rh-identity` authenticated principals when `type` is `Associate`. - `test` - granted to any authenticated principal when `SWATCH_TEST_APIS_ENABLED` is `true`. Note that for each auth method, classes were added for each of: - `AuthenticationRequest`-suffixed class to represent an attempt to authenticate. - `Principal`-suffixed class to represent an authenticated. - `AuthenticationMechanism`-suffixed class to create authentication requests. - `IdentityProvider`-suffixed class to handle authentication success/failure logic. The `SWATCH_TEST_APIS_ENABLED` value is defaulted to false in `stage` and `prod` profiles. ([SWATCH-882](https://issues.redhat.com/browse/SWATCH-882) will change it to `true` in stage). I set up `MdcFilter` to add the principal to logging MDC, if authenticated. I also added a new package `security` to encapsulate all things in authn/authz domain. Note: I looked at getting more helpful auth failed responses, but it seems to not be supported due to when auth happens in the quarkus resteasy lifecycle. While not ideal, I think this is acceptable for internal APIs, as 401 can be interpreted as authn not provided or authn failed, and 403 as authn succeeded, but authz failed. Though it seems we can customize if we switch to resteasy-reactive and disable proactive authentication; see: quarkusio/quarkus#25732 and https://quarkus.io/guides/security-built-in-authentication-support-concept#how-to-customize-authentication-exception-responses. I opened [SWATCH-1025](https://issues.redhat.com/browse/SWATCH-1025) and [SWATCH-1026](https://issues.redhat.com/browse/SWATCH-1026) to revisit later on. Logging uses the principal name, and I implemented three strategies: - For associate identities, the principal name is the email address. - For X509 (mTLS) identities, the principal name is the subject DN (distinguished name). - For PSK identities, the principal name is `urn:console.redhat.com:service:swatch` Note, I set `quarkus.security.auth.enabled-in-dev-mode=false`, which makes development more convenient by not requiring auth in dev mode. This can be toggled by setting `QUARKUS_SECURITY_AUTH_ENABLED_IN_DEV_MODE=true`. Testing ======= For convenience, first export the following environment variables into a shell to be used to make requests: ```shell export PSK_HEADER=x-rh-swatch-psk:placeholder export PSK_HEADER_BAD=x-rh-swatch-psk:wrong export SUPPORT_HEADER=x-rh-identity:$(echo ' { "identity": { "type": "Associate", "associate" : { "email": "test@example.com" } } }' | base64 -w0) export X509_HEADER=x-rh-identity:$(echo ' { "identity": { "type": "X509", "x509" : { "subject_dn": "CN=test.example.com" } } }' | base64 -w0) ``` First, test with `SWATCH_TEST_APIS_ENABLED=true` (default): In a separate shell, start the service with debug logging turned on for com.redhat.swatch, and overriding RBAC to be on in dev mode: ```shell LOGGING_LEVEL_COM_REDHAT_SWATCH=DEBUG \ QUARKUS_SECURITY_AUTH_ENABLED_IN_DEV_MODE=true \ ./gradlew swatch-contracts:quarkusDev ``` First, try the DELETE endpoint without auth and then with incorrect psk: ```shell http DELETE :8000/api/rhsm-subscriptions/v1/internal/contracts/8ece4096-bef6-4ad6-b0db-20c8e6b2a78c http DELETE :8000/api/rhsm-subscriptions/v1/internal/contracts/8ece4096-bef6-4ad6-b0db-20c8e6b2a78c \ $PSK_HEADER_BAD ``` Both give 401 response, indicating auth is required, but not provided or rejected. Next, try the DELETE endpoint with a good PSK: ```shell http DELETE :8000/api/rhsm-subscriptions/v1/internal/contracts/8ece4096-bef6-4ad6-b0db-20c8e6b2a78c \ $PSK_HEADER ``` This time, you get a 204, and note a few important lines in the log: `test` and `service` roles are granted to the PSK: > Granting roles [test, service] to user: urn:console.redhat.com:service:swatch Subsequent log messages indicate what user was involved (via MDC): > {user=urn:console.redhat.com:service:swatch} Repeat this test, but with associate and x509 identities: ```shell http DELETE :8000/api/rhsm-subscriptions/v1/internal/contracts/8ece4096-bef6-4ad6-b0db-20c8e6b2a78c \ $SUPPORT_HEADER http DELETE :8000/api/rhsm-subscriptions/v1/internal/contracts/8ece4096-bef6-4ad6-b0db-20c8e6b2a78c \ $X509_HEADER ``` Look at the logs and observe the roles granted, and principal name differences. Now, repeat all of the above steps with the test role disabled (you can either set `SWATCH_TEST_APIS_ENABLED=false` and restart the service, or you can change the config via http://localhost:8000/q/dev/io.quarkus.quarkus-vertx-http/config). Notice that no principals can use the `DELETE` endpoint. Also notice that no principals are granted the `test` role. You can test further role combinations as desired. An easy way to test a bunch quickly is to modify the `@RolesAllowed` values on `ContractsTestingResource.deleteContractByUUID`, and adjusting the roles on a principal by modifying `RolesAugmentor`.
https://issues.redhat.com/browse/SWATCH-849 I had to move `openapi.yaml` to `src/main/resources/META-INF` so that it would be picked up by `OpenApiDocumentService`, so that API definitions could be easily referenced from unit tests (e.g. see `ResourceRolesAllowedTest`). This also makes http://localhost:8000/q/openapi serve more complete API including security schemes. Three roles are defined: - `service` - granted to `x-rh-swatch-psk` authenticated principals - `support` - granted to `x-rh-identity` authenticated principals when `type` is `Associate`. - `test` - granted to any authenticated principal when `SWATCH_TEST_APIS_ENABLED` is `true`. Note that for each auth method, classes were added for each of: - `AuthenticationRequest`-suffixed class to represent an attempt to authenticate. - `Principal`-suffixed class to represent an authenticated. - `AuthenticationMechanism`-suffixed class to create authentication requests. - `IdentityProvider`-suffixed class to handle authentication success/failure logic. The `SWATCH_TEST_APIS_ENABLED` value is defaulted to false in `stage` and `prod` profiles. ([SWATCH-882](https://issues.redhat.com/browse/SWATCH-882) will change it to `true` in stage). I set up `MdcFilter` to add the principal to logging MDC, if authenticated. I also added a new package `security` to encapsulate all things in authn/authz domain. Note: I looked at getting more helpful auth failed responses, but it seems to not be supported due to when auth happens in the quarkus resteasy lifecycle. While not ideal, I think this is acceptable for internal APIs, as 401 can be interpreted as authn not provided or authn failed, and 403 as authn succeeded, but authz failed. Though it seems we can customize if we switch to resteasy-reactive and disable proactive authentication; see: quarkusio/quarkus#25732 and https://quarkus.io/guides/security-built-in-authentication-support-concept#how-to-customize-authentication-exception-responses. I opened [SWATCH-1025](https://issues.redhat.com/browse/SWATCH-1025) and [SWATCH-1026](https://issues.redhat.com/browse/SWATCH-1026) to revisit later on. Logging uses the principal name, and I implemented three strategies: - For associate identities, the principal name is the email address. - For X509 (mTLS) identities, the principal name is the subject DN (distinguished name). - For PSK identities, the principal name is `urn:console.redhat.com:service:swatch` Note, I set `quarkus.security.auth.enabled-in-dev-mode=false`, which makes development more convenient by not requiring auth in dev mode. This can be toggled by setting `QUARKUS_SECURITY_AUTH_ENABLED_IN_DEV_MODE=true`. Testing ======= For convenience, first export the following environment variables into a shell to be used to make requests: ```shell export PSK_HEADER=x-rh-swatch-psk:placeholder export PSK_HEADER_BAD=x-rh-swatch-psk:wrong export SUPPORT_HEADER=x-rh-identity:$(echo ' { "identity": { "type": "Associate", "associate" : { "email": "test@example.com" } } }' | base64 -w0) export X509_HEADER=x-rh-identity:$(echo ' { "identity": { "type": "X509", "x509" : { "subject_dn": "CN=test.example.com" } } }' | base64 -w0) ``` First, test with `SWATCH_TEST_APIS_ENABLED=true` (default): In a separate shell, start the service with debug logging turned on for com.redhat.swatch, and overriding RBAC to be on in dev mode: ```shell LOGGING_LEVEL_COM_REDHAT_SWATCH=DEBUG \ QUARKUS_SECURITY_AUTH_ENABLED_IN_DEV_MODE=true \ ./gradlew swatch-contracts:quarkusDev ``` First, try the DELETE endpoint without auth and then with incorrect psk: ```shell http DELETE :8000/api/rhsm-subscriptions/v1/internal/contracts/8ece4096-bef6-4ad6-b0db-20c8e6b2a78c http DELETE :8000/api/rhsm-subscriptions/v1/internal/contracts/8ece4096-bef6-4ad6-b0db-20c8e6b2a78c \ $PSK_HEADER_BAD ``` Both give 401 response, indicating auth is required, but not provided or rejected. Next, try the DELETE endpoint with a good PSK: ```shell http DELETE :8000/api/rhsm-subscriptions/v1/internal/contracts/8ece4096-bef6-4ad6-b0db-20c8e6b2a78c \ $PSK_HEADER ``` This time, you get a 204, and note a few important lines in the log: `test` and `service` roles are granted to the PSK: > Granting roles [test, service] to user: urn:console.redhat.com:service:swatch Subsequent log messages indicate what user was involved (via MDC): > {user=urn:console.redhat.com:service:swatch} Repeat this test, but with associate and x509 identities: ```shell http DELETE :8000/api/rhsm-subscriptions/v1/internal/contracts/8ece4096-bef6-4ad6-b0db-20c8e6b2a78c \ $SUPPORT_HEADER http DELETE :8000/api/rhsm-subscriptions/v1/internal/contracts/8ece4096-bef6-4ad6-b0db-20c8e6b2a78c \ $X509_HEADER ``` Look at the logs and observe the roles granted, and principal name differences. Now, repeat all of the above steps with the test role disabled (you can either set `SWATCH_TEST_APIS_ENABLED=false` and restart the service, or you can change the config via http://localhost:8000/q/dev/io.quarkus.quarkus-vertx-http/config). Notice that no principals can use the `DELETE` endpoint. Also notice that no principals are granted the `test` role. You can test further role combinations as desired. An easy way to test a bunch quickly is to modify the `@RolesAllowed` values on `ContractsTestingResource.deleteContractByUUID`, and adjusting the roles on a principal by modifying `RolesAugmentor`.
Describe the bug
I tried to add a custom exception mapper for unauthenticated exceptions. Followed the instruction on https://quarkus.io/guides/security-built-in-authentication#how-to-customize-authentication-exception-responses. However, although the exception mapper is defined, it's never being invoked. Switching the proactive auth on and off does not have any impact.
The exception mapper is the same as in the documentation:
Expected behavior
Response can be customized.
Actual behavior
Always returns the same response:
How to Reproduce?
Here is the reproducible example: https://github.com/ivansenic/quarkus-25732
Output of
uname -a
orver
Linux ise-Precision-5550 5.13.0-41-generic #46~20.04.1-Ubuntu SMP Wed Apr 20 13:16:21 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Output of
java -version
openjdk version "17.0.3" 2022-04-19 OpenJDK Runtime Environment (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1) OpenJDK 64-Bit Server VM (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1, mixed mode, sharing)
GraalVM version (if different from Java)
No response
Quarkus version or git rev
2.9.1.Final
Build tool (ie. output of
mvnw --version
orgradlew --version
)Maven home: /home/ise/.m2/wrapper/dists/apache-maven-3.8.4-bin/52ccbt68d252mdldqsfsn03jlf/apache-maven-3.8.4 Java version: 17.0.3, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64 Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "5.13.0-41-generic", arch: "amd64", family: "unix"
Additional information
No response
The text was updated successfully, but these errors were encountered: