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

Conflict between form-based auth logout and quarkus.http.auth.form.new-cookie-interval #42613

Closed
ksdev-pl opened this issue Aug 18, 2024 · 2 comments · Fixed by #46429
Closed
Labels
area/security kind/bug Something isn't working
Milestone

Comments

@ksdev-pl
Copy link
Contributor

ksdev-pl commented Aug 18, 2024

Describe the bug

Hello. Maybe I'm missing something, but have a look (example project at https://github.com/ksdev-pl/quarkus-logout-conflict):

Let's say we have a simple form-based authentication with logout method implemented according to the documentation (https://quarkus.io/guides/security-authentication-mechanisms#form-auth):

    @GET
    @Path("logout")
    public Response logout() {
        if (identity.getIdentity().isAnonymous()) {
            throw new UnauthorizedException("Not authenticated");
        }
        final NewCookie removeCookie = new NewCookie.Builder(authCookieName)
            .maxAge(0)
            .expiry(Date.from(Instant.EPOCH))
            .path("/")
            .build();
        return Response.seeOther(URI.create("/auth/login"))
            .cookie(removeCookie)
            .build();
    }

Let's test it:

  1. We login using POST http://localhost:8080/j_security_check - this sets the quarkus-credential cookie.
  2. After successful login we access the protected page.
  3. On the protected page we click on "logout", which destroys the cookie and redirects us back to the /login page.
    Logout response headers look like this:
HTTP/1.1 303 See Other
Location: http://localhost:8080/auth/login
Set-Cookie: quarkus-credential=;Version=1;Path=/;Max-Age=0;Expires=Thu, 01-Jan-1970 00:00:00 GMT
content-length: 0

Everything is fine and dandy, we're logged out.

Now let's take the quarkus.http.auth.form.new-cookie-interval into consideration, which by default is 1 minute:

  1. We login using POST http://localhost:8080/j_security_check - this sets the quarkus-credential cookie.
  2. After successful login we access the protected page.
  3. We wait more than 1 minute.
  4. On the protected page we click on "logout", which should destroy the cookie and redirects us back to the /login page.
    Logout response headers look like this:
HTTP/1.1 303 See Other
Location: http://localhost:8080/auth/login
Set-Cookie: quarkus-credential=;Version=1;Path=/;Max-Age=0;Expires=Thu, 01-Jan-1970 00:00:00 GMT
content-length: 0
set-cookie: quarkus-credential=DD0QkzbLhLqcmjoqf6QvrSHRsLZRm0VmXp9ILRCpfMKh4A8dGI9kwHMSo5g89hKt; Path=/; SameSite=Strict

We see the login screen, job well done, we implemented the logout? Nope, the user is still logged in and protected resources are still accessible (and stays logged in for the duration of quarkus.http.auth.form.timeout).

You see the issue in the headers - "destroy" cookie is overwritten by the "new-cookie-interval-cookie", or whatever is its name (at least I guess that it's new-cookie-interval functionality).

It looks like using default Quarkus configuration (new-cookie-interval equal to 1 minute) and example from documentation (logout code) we can easily arrive at a not-obviously non-working logout.

Expected behavior

Auth cookie is destroyed during logout.

Actual behavior

Auth cookie is not destroyed during logout if request was made after new-cookie-interval time.

How to Reproduce?

Steps in description above. Basic example project: https://github.com/ksdev-pl/quarkus-logout-conflict

Output of uname -a or ver

Linux fedora 6.10.4-200.fc40.x86_64 #1 SMP PREEMPT_DYNAMIC Sun Aug 11 15:32:50 UTC 2024 x86_64 GNU/Linux

Output of java -version

openjdk 21.0.1 2023-10-17 LTS

Quarkus version or git rev

Quarkus 3.13.2

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

Apache Maven 3.9.6 (Red Hat 3.9.6-6)

Additional information

No response

@ksdev-pl ksdev-pl added the kind/bug Something isn't working label Aug 18, 2024
@ksdev-pl ksdev-pl changed the title Conflict between form-base auth logout and quarkus.http.auth.form.new-cookie-interval Conflict between form-based auth logout and quarkus.http.auth.form.new-cookie-interval Aug 18, 2024
@michalvavrik
Copy link
Member

hey @ksdev-pl, sorry I missed this issue. I'll try to have a look within a week and get back to you. Thanks for the reproducer.

@michalvavrik
Copy link
Member

michalvavrik commented Feb 21, 2025

the issue here is that Quarkus REST adds cookies as Set-Cookie header, but io.vertx.core.http.impl.Http1xServerResponse "overrides it" (for lack of better word) as cookies are set after headers. so first it looks like this (headers added by Quarkus REST):

Location=http://localhost:8081/
Set-Cookie=quarkus-credential=;Version=1;Path=/;Max-Age=0;Expires=Thu, 01-Jan-1970 00:00:00 GMT
content-length=0

and once io.vertx.core.http.impl.Http1xServerResponse is done:

Location=http://localhost:8081/
Set-Cookie=quarkus-credential=;Version=1;Path=/;Max-Age=0;Expires=Thu, 01-Jan-1970 00:00:00 GMT
content-length=0
set-cookie=quarkus-credential=DIQxGASGYcr8X+kQ62QuVbVB22Psgym+yTc1Dk+hYai6UbXrsRyrdFLTe2USvvU=; Path=/; SameSite=Strict

So even though technically authentication refreshes cookie first, it overrides the header response added after that.
I have actually wasted many hours today on trying to adjust Quarkus REST by adding org.jboss.resteasy.reactive.server.spi.ServerHttpResponse#addResponseCookie and it works, but I don't think I want to introduce that. Problem is that io.vertx.core.http.Cookie doesn't support Expires, Partitioned and Version attributes. So fixing it this way would require encoding stuff ourselves and introducing own equals, dealing with quoting etc. It is easier for servlets.

Maybe @geoand will decide to fix that discrepancy, but as for login, I think I'll just introduce utility method and rewrite docs.

@ksdev-pl thanks for reporting this and apologies for waiting

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/security kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants