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

OIDC login not work #30797

Closed
jie-huang opened this issue Feb 2, 2023 · 11 comments · Fixed by #30828
Closed

OIDC login not work #30797

jie-huang opened this issue Feb 2, 2023 · 11 comments · Fixed by #30828
Labels
area/oidc kind/bug Something isn't working
Milestone

Comments

@jie-huang
Copy link

Describe the bug

A simple OIDC app works at version 2.11.1.Final.
But, it fails at version 2.13.7.Final, 2.16.1.Final.

Expected behavior

It should work.

Actual behavior

  • 2.13.7.Final, /oidc/login-callback path cannot find, 404
  • 2.16.1.Final, redirect between /test/login and /oidc/login-callback,
    Firefox has detected that the server is redirecting the request for this address in a way that will never complete.

How to Reproduce?

Please ref https://github.com/jie-huang/quarkus-oidc for example project.
Or, you can generate a simple OIDC web-app.

@Path("/test")
public class Session {
  @Inject
  OidcSession oidcSession;

  @GET
  @Path("/login")
  @RolesAllowed("**")
  public Response login() throws URISyntaxException {
    return Response.seeOther(new URI("/test/data")).build();
  }

  @GET
  @Path("/data")
  @RolesAllowed("**")
  public Response data() {
    return Response.ok("<!doctype html><html><head><title>test</title></head><body>login successfully</body></html>")
      .header("Content-Type", "text/html;charset=UTF-8").build();
  }
}

main config

quarkus.oidc.application-type=web-app
quarkus.oidc.auth-server-url=xxxxxx
quarkus.oidc.authentication.pkce-required=true
quarkus.oidc.authentication.pkce-secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
quarkus.oidc.authentication.user-info-required=true
quarkus.oidc.client-id=xxxxxx
quarkus.oidc.roles.role-claim-path=groups
quarkus.oidc.roles.source=userinfo
quarkus.oidc.tls.verification=none

quarkus.oidc.authentication.error-path=/oidc/auth_error
quarkus.oidc.authentication.redirect-path=/oidc/login-callback
quarkus.oidc.authentication.restore-path-after-redirect=true
quarkus.oidc.authentication.scopes=email,offline_access
quarkus.oidc.logout.path=/oidc/logout
quarkus.oidc.logout.post-logout-path=/

In firefox, access path /test/login, it should login successfully and redirect to /test/data.

Output of uname -a or ver

Darwin sd-lmc-1a8902 21.6.0 Darwin Kernel Version 21.6.0: Mon Dec 19 20:46:01 PST 2022; root:xnu-8020.240.18~2/RELEASE_ARM64_T8101 arm64

Output of java -version

openjdk version "18" 2022-03-22

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.13.7.Final, 2.16.1.Final

Build tool (ie. output of mvnw --version or gradlew --version)

Gradle 7.4.1

Additional information

No response

@jie-huang jie-huang added the kind/bug Something isn't working label Feb 2, 2023
@quarkus-bot quarkus-bot bot added the area/oidc label Feb 2, 2023
@quarkus-bot
Copy link

quarkus-bot bot commented Feb 2, 2023

/cc @pedroigor (oidc), @sberyozkin (oidc)

@sberyozkin
Copy link
Member

sberyozkin commented Feb 2, 2023

@jie-huang There was a bit of a problem in 2.16.0 related to the loop and the state cookie being same site strict.
2.16.1 does not have that problem.
I wonder, is the login() reached ? Can you update it to return some hello string, instead of the custom redirect, just to check it it will work in that case ?
It might be a redirect one too many, Firefox redirects the user to OIDC and back to Quarkus, then Quarkus redirects to itself under the hood to drop the OIDC query parameters, and now the custom code redirects to itself again.
Also check in the browser web console what is going on, and enable the debug logs:

quarkus.log.category."io.quarkus.oidc.runtime.CodeAuthenticationMechanism".level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.CodeAuthenticationMechanism".min-level=TRACE

@sschellh
Copy link

sschellh commented Feb 2, 2023

Hello @sberyozkin

With version 2.15.3.Final I am facing no login issues. However, with version 2.16.1.Final the OIDC login is not working anymore.

It fails with following message in the browser (chrome):

Diese Seite funktioniert nicht
localhost hat dich zu oft weitergeleitet.
Lösche deine Cookies.
ERR_TOO_MANY_REDIRECTS

@jie-huang
Copy link
Author

@jie-huang There was a bit of a problem in 2.16.0 related to the loop and the state cookie being same site strict. 2.16.1 does not have that problem. I wonder, is the login() reached ? Can you update it to return some hello string, instead of the custom redirect, just to check it it will work in that case ? It might be a redirect one too many, Firefox redirects the user to OIDC and back to Quarkus, then Quarkus redirects to itself under the hood to drop the OIDC query parameters, and now the custom code redirects to itself again. Also check in the browser web console what is going on, and enable the debug logs:

quarkus.log.category."io.quarkus.oidc.runtime.CodeAuthenticationMechanism".level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.CodeAuthenticationMechanism".min-level=TRACE

@sberyozkin Thanks for your quick response.
I tested on 2.16.1, I can reproduce it.

  1. I updated it to return just a simple result instead of custom redirect. It is same problem.
  2. I enabled the logs.

In Firefox console,

http://localhost:8200/oidc/login-callback?code=...&state=...
http://localhost:8200/test/login
https://dev-xxxxx.okta.com/oauth2/default/v1/authorize?response_type=code&client_id=...&scope=openid+email+offline_access&redirect_uri=http%3A%2F%2Flocalhost%3A8200%2Ftsaaa%2Flogin-callback&state=...&code_challenge=...&code_challenge_method=S256
http://localhost:8200/oidc/login-callback?code=...&state=...

It just keep repeat the three URLs util Firefox decide to stop.

In server console, it repeats below

2023-02-02 09:01:02,459 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) Code flow redirect to: https://dev-xxxxxx.okta.com/oauth2/default/v1/authorize?response_type=code&client_id=...&scope=openid+email+offline_access&redirect_uri=http%3A%2F%2Flocalhost%3A8200%2Ftsaaa%2Flogin-callback&state=...&code_challenge=...&code_challenge_method=S256

2023-02-02 09:01:02,461 INFO  [io.qu.ht.access-log] (vert.x-eventloop-thread-2) 127.0.0.1 - - 02/Feb/2023:09:01:02 -0800 "/test/login" 302
2023-02-02 09:01:03,117 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) State cookie is present, processing an expected redirect from the OIDC provider
2023-02-02 09:01:03,118 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) Authorization code is present, completing the code flow
2023-02-02 09:01:03,119 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) Exchanging the authorization code for the tokens
2023-02-02 09:01:03,120 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) Token request redirect_uri parameter: http://localhost:8200/oidc/login-callback
2023-02-02 09:01:03,286 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) Authorization code has been exchanged, verifying ID token
2023-02-02 09:01:03,724 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) ID token has been verified, removing the existing session cookie if any and creating a new one
2023-02-02 09:01:03,726 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) ID token is valid for 3600 seconds
2023-02-02 09:01:03,727 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) q_session cookie 'max-age' parameter is set to 3600
2023-02-02 09:01:03,728 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) Removing code flow redirect parameters, final redirect URI: http://localhost:8200/test/login
2023-02-02 09:01:03,729 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) Starting the final redirect
2023-02-02 09:01:03,731 INFO  [io.qu.ht.access-log] (vert.x-eventloop-thread-2) 127.0.0.1 - - 02/Feb/2023:09:01:03 -0800 "/oidc/login-callback" 302
2023-02-02 09:01:03,736 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) Starting an authentication challenge
2023-02-02 09:01:03,737 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) Authentication request redirect_uri parameter: http://localhost:8200/oidc/login-callback
2023-02-02 09:01:03,739 DEBUG [io.qu.oi.ru.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) q_auth cookie 'max-age' parameter is set to 1800

Based on firefox request details, when sending request to /test/login, there is no cookie 'q_session' is sent to quarkus, even the previous login-callback response has cookie 'q_session' with httpOnly:true, path: "/", samesite: "Strict".

So, the cookie setting has problem so browser does not send it back. That makes quarkus to re-do the auth loop.

@sberyozkin
Copy link
Member

@jie-huang Thanks, I think I know what might be going on, it must be to do with

quarkus.oidc.authentication.redirect-path=/oidc/login-callback
quarkus.oidc.authentication.restore-path-after-redirect=true

So you first try to access /test/data, initial redirect goes back to /oidc/login-callback at which point the config requires restoring /test/data, so the redirect goes here again, it is really the same site (host, port), only relative paths differ
and it looks like the samesite=strict simply not work with any redirects at all, even same site one.

It's proving to be a very unfortunate update I did. We had good intentions, tests pass, simple demos pass in quickstarts.

But it is just causes too many side-effects, any complex application redirecting a lot will now be losing it.

So I have no choice but default all OIDC cookies to same site lax - it will remain configurable for the session cookie which will work with simple cases.

For now the workaround remains the same,

quarkus.oidc.authentication.cookie-same-site=lax

@sberyozkin
Copy link
Member

sberyozkin commented Feb 2, 2023

CC @gastaldi @pmlopes Hi, I'll have to now follow #30722 with making the session cookie same site lax as well, otherwise we will be overwhelmed with bug reports.
samesite=strict only works for applications without local redirects or with redirects to the same path (ex, drop query parameters).
Paulo, the good news though is that quarkus.oidc.authentication.cookie-same-site will remain configurable which is critical in its own way

@jie-huang
Copy link
Author

@sberyozkin Thanks for the explain.
quarkus.oidc.authentication.cookie-same-site=lax works.
Totally understand the complex. I have unit test to check login too, it did not find this either because the test lib cannot handle cookie like browser. :(

BTW, how about version 2.13.7, the error is 404 "cannot find /oidc/login-callback" even the config can fix it. But the problem seems different.

@sberyozkin
Copy link
Member

@jie-huang Thanks

Totally understand the complex. I have unit test to check login too, it did not find this either because the test lib cannot handle cookie like browser. :(

Right, but the session cookie in your demo is same site, strict must work, the fact that you have

GET /oidc/login-callback returning the session cookie on the root context (path=/), same site strict, but status code 302 redirecting to /test/data and it is enough to lose the session cookie is something which makes no sense at all, but we can't afford asking users to keep trying different browser versions, etc, it has to work OOB, while keeping the option open to the users to experiment with making the session cookie same site strict.

BTW, how about version 2.13.7, the error is 404 "cannot find /oidc/login-callback" even the config can fix it. But the problem seems different.

this might be caused by some misconfiguration, this path can be a virtual path, not declared on any endpoint, but as far as OIDC is concerned it has to be recognized as requiring the protection, which is done for such paths with HTTP policy, so if something does not match then it will skip processing it and the request will flow to the JAX-RS chain with 404 to follow. Something like that. If you have identical configurations between 2.13.7 and 2.16.1 with this same site lax config being the only difference and it works in 2.16.1, then it means something has been fixed by now...

@sberyozkin
Copy link
Member

sberyozkin commented Feb 2, 2023

@jie-huang I think if you did not have a custom callback path introduced then the redirect from OIDC would go directly to /test/data?code=..., here Quarkus would redirect to /test/data dropping the query parameters, and this does not lose the same session strict session cookie because the redirect goes to exactly the same path, I believe I confirmed it earlier with the browser, perhaps a redirect to test/data/hello would also work because the test/data is a base, but it would fail anyway once the custom redirect is made somewhere else to within the same site but different route.

@jie-huang
Copy link
Author

@sberyozkin

I just wrote a small app to test the sameSite=Strict behavior and test locally, both a.com and b.com are localhost.
a.com:8000/c, redirect to b.com:8080/d

b.com:8080/d (set cookie 'b'='b') then redirect to b.com:8080/c
b.com:8080/c, show cookie value in request
b.com:8080/b, redirect to b.com:8080/d
The test result is interesting,

  1. Input b.com:8080/b, all browsers reach b.com:8080/c finally, and show cookie value 'b'
  2. Input a.com:8000/c, all browsers reach b.com:8080/c finally. But
    • in firefox and safari, there is no cookie shows
    • in chrome, there is cookie shows

So, it seems different browsers handle the sameSite redirect differently when the beginning non-redirect request coming from another domain. That is the case here. All the requests are coming from IdP (a.com in the example) with redirect back to quarkus oidc (b.com in the example), then, quarkus idc redirect to another quarkus url (b.com). How many redirect inside b.com does not matter. The only matter one is, the first non-redirect request is from b.com or a.com.

@sberyozkin
Copy link
Member

Thanks for this analysis, @jie-huang. Right, what it does confirm is that it becomes fairly unpredictable, and it will not something I'd like quarkus-oidc to have, the unpredictability. So I'm going to resolve this issue shortly but for cases where it may work, ex, Chrome is a required browser in some productions, or in simpler cases, the users will be able to set same site strict, which is good, so @pmlopes, Paulo, we can still give users this option of the same site strict :-)

@quarkus-bot quarkus-bot bot added this to the 3.0 - main milestone Feb 2, 2023
@gsmet gsmet modified the milestones: 3.0 - main, 2.16.2.Final Feb 7, 2023
benkard added a commit to benkard/mulkcms2 that referenced this issue Apr 2, 2023
This MR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [com.diffplug.spotless:spotless-maven-plugin](https://github.com/diffplug/spotless) | build | minor | `2.32.0` -> `2.33.0` |
| [io.quarkus:quarkus-maven-plugin](https://github.com/quarkusio/quarkus) | build | patch | `2.16.1.Final` -> `2.16.2.Final` |
| [io.quarkus:quarkus-universe-bom](https://github.com/quarkusio/quarkus-platform) | import | patch | `2.16.1.Final` -> `2.16.2.Final` |

---

### Release Notes

<details>
<summary>diffplug/spotless</summary>

### [`v2.33.0`](https://github.com/diffplug/spotless/blob/HEAD/CHANGES.md#&#8203;2330---2023-01-26)

##### Added

-   `ProcessRunner` has added some convenience methods so it can be used for maven testing. ([#&#8203;1496](diffplug/spotless#1496))
-   `ProcessRunner` allows to limit captured output to a certain number of bytes. ([#&#8203;1511](diffplug/spotless#1511))
-   `ProcessRunner` is now capable of handling long-running tasks where waiting for exit is delegated to the caller. ([#&#8203;1511](diffplug/spotless#1511))
-   Allow to specify node executable for node-based formatters using `nodeExecutable` parameter ([#&#8203;1500](diffplug/spotless#1500))

##### Fixed

-   The default list of type annotations used by `formatAnnotations` has had 8 more annotations from the Checker Framework added [#&#8203;1494](diffplug/spotless#1494)

##### Changes

-   **POTENTIALLY BREAKING** Bump minimum JRE from 8 to 11, next release likely to bump bytecode to Java 11 ([#&#8203;1514](diffplug/spotless#1514) part 1 of [#&#8203;1337](diffplug/spotless#1337))
-   Rename `YamlJacksonStep` into `JacksonYamlStep` while normalizing Jackson usage ([#&#8203;1492](diffplug/spotless#1492))
-   Convert `gson` integration to use a compile-only source set ([#&#8203;1510](diffplug/spotless#1510)).
-   \*\* POTENTIALLY BREAKING\*\* Removed support for KtLint 0.3x and 0.45.2 ([#&#8203;1475](diffplug/spotless#1475))
    -   `KtLint` does not maintain a stable API - before this MR, we supported every breaking change in the API since 2019.
    -   From now on, we will support no more than 2 breaking changes at a time.
-   NpmFormatterStepStateBase delays `npm install` call until the formatter is first used. This enables better integration
    with `gradle-node-plugin`. ([#&#8203;1522](diffplug/spotless#1522))
-   Bump default `ktlint` version to latest `0.48.1` -> `0.48.2` ([#&#8203;1529](diffplug/spotless#1529))
-   Bump default `scalafmt` version to latest `3.6.1` -> `3.7.1` ([#&#8203;1529](diffplug/spotless#1529))

</details>

<details>
<summary>quarkusio/quarkus</summary>

### [`v2.16.2.Final`](https://github.com/quarkusio/quarkus/releases/tag/2.16.2.Final)

[Compare Source](quarkusio/quarkus@2.16.1.Final...2.16.2.Final)

##### Complete changelog

-   [#&#8203;30976](quarkusio/quarkus#30976) - Metrics - check if index contains class before attempting to use it
-   [#&#8203;30965](quarkusio/quarkus#30965) - JandexBeanInfoAdapter.getMetricAnnotationsThroughStereotype is not null safe
-   [#&#8203;30959](quarkusio/quarkus#30959) - Return text from /q/metrics when the Accept header contains html
-   [#&#8203;30953](quarkusio/quarkus#30953) - Fix OIDC capability string
-   [#&#8203;30947](quarkusio/quarkus#30947) - Ignore interface/class without default constructs fields in SB config
-   [#&#8203;30940](quarkusio/quarkus#30940) - Use SchemaType.ARRAY instead of "ARRAY" for native support
-   [#&#8203;30919](quarkusio/quarkus#30919) - Compilation to native fails, when quarkus-smallrye-openapi is included
-   [#&#8203;30916](quarkusio/quarkus#30916) - Add AppCDS documentation
-   [#&#8203;30896](quarkusio/quarkus#30896) - Quarkus spring-boot-properties extension unable to handle complex configuration.
-   [#&#8203;30878](quarkusio/quarkus#30878) - Bump postgresql from 42.5.2 to 42.5.3
-   [#&#8203;30866](quarkusio/quarkus#30866) - Only run the quickstart compilation for main
-   [#&#8203;30851](quarkusio/quarkus#30851) - Fixed return type typo in smallrye graphQL guide
-   [#&#8203;30844](quarkusio/quarkus#30844) - Fixed greeting in getting started guide
-   [#&#8203;30839](quarkusio/quarkus#30839) - Fix handling of Accept header in graphQL
-   [#&#8203;30833](quarkusio/quarkus#30833) - Update docs to show BuildProducer use as method parameter instead of field
-   [#&#8203;30828](quarkusio/quarkus#30828) - Make OIDC session cookie same site lax by default
-   [#&#8203;30826](quarkusio/quarkus#30826) - Caffeine - Automatically register metrics cache impls if Micrometer is around
-   [#&#8203;30825](quarkusio/quarkus#30825) - Fix comment about Caffeine optimization
-   [#&#8203;30823](quarkusio/quarkus#30823) - Change accept header to valid plain text in micrometer documentation
-   [#&#8203;30821](quarkusio/quarkus#30821) - Packaging type -Dquarkus.package.create-appcds=true isn't documented
-   [#&#8203;30815](quarkusio/quarkus#30815) - Update SmallRye Config to 2.13.2
-   [#&#8203;30812](quarkusio/quarkus#30812) - Manage the apache-mime4j dependency
-   [#&#8203;30806](quarkusio/quarkus#30806) - */* in Accept header is ignored if not listed as the first item
-   [#&#8203;30805](quarkusio/quarkus#30805) - MailTemplateInstance with attachments
-   [#&#8203;30803](quarkusio/quarkus#30803) - Support file and byte array attachments in `MailTemplateInstance`
-   [#&#8203;30797](quarkusio/quarkus#30797) - OIDC login not work
-   [#&#8203;30783](quarkusio/quarkus#30783) - <artifactId> uses 'quarkus.platform.artifact-id' property
-   [#&#8203;30778](quarkusio/quarkus#30778) - Avoid creating 3 Liquibase MongoDB instances for startup operations
-   [#&#8203;30776](quarkusio/quarkus#30776) - Ensure that AwsProxyRequestContext can be used with [@&#8203;Context](https://github.com/Context) in RESTEasy Reactive
-   [#&#8203;30767](quarkusio/quarkus#30767) - Remove duplicate notification of SseBroadcaster's onErrorListeners
-   [#&#8203;30765](quarkusio/quarkus#30765) - Bump postgresql from 42.5.1 to 42.5.2
-   [#&#8203;30755](quarkusio/quarkus#30755) - Update ForwardedParser to validate the port
-   [#&#8203;30744](quarkusio/quarkus#30744) - \[Quarkus Native] ClassNotFoundException: com.github.benmanes.caffeine.cache.SSSW
-   [#&#8203;30536](quarkusio/quarkus#30536) - munitnyucontextmanager non helpful error reporting
-   [#&#8203;29753](quarkusio/quarkus#29753) - Introduce ConnectionFactoryWrapperBuildItem
-   [#&#8203;29605](quarkusio/quarkus#29605) - Update docs to reflect that injection should not
-   [#&#8203;27774](quarkusio/quarkus#27774) - PLANNER-1709 Avoid deprecated penalize/reward overloads
-   [#&#8203;23442](quarkusio/quarkus#23442) - problem using quarkus-resteasy-reactive-kotlin-serialization with AwsProxyRequestContext

</details>

<details>
<summary>quarkusio/quarkus-platform</summary>

### [`v2.16.2.Final`](quarkusio/quarkus-platform@2.16.1.Final...2.16.2.Final)

[Compare Source](quarkusio/quarkus-platform@2.16.1.Final...2.16.2.Final)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever MR is behind base branch, or you tick the rebase/retry checkbox.

👻 **Immortal**: This MR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC4yNC4wIiwidXBkYXRlZEluVmVyIjoiMzQuMjQuMCJ9-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/oidc kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants