Leantime / leantime

Leantime is a goals focused project management system for non-project managers. Building with ADHD, Autism, and dyslexia in mind.
https://leantime.io
GNU Affero General Public License v3.0
4.29k stars 567 forks source link

[BUG] Leantime logs out with every page change and injects %2F into the URLs repeatedly. #2504

Open JustEnoughDucks opened 2 months ago

JustEnoughDucks commented 2 months ago

If you have problems with the installation please use our community forum

What set up are you using

Describe the bug 2FA is not enabled!

After initial login which takes 5-10 logins and a refresh because it keeps appending a %2F redirect after every login attempt, (https://my.domain.here/auth/login?redirect=%2F%2F%2F%2F%2F)clicking on any button that would trigger a refresh results in a redirect to the base URL such as https://my.domain.here/auth/login?redirect=%2Fprojects%2FchangeCurrentProject%2F10

This means per session, I have to log in anywhere from 40-100 times. There are no errors in the logs

To Reproduce Steps to reproduce the behavior:

  1. Go to base domain
  2. Login
  3. Redirect to base URL
  4. Repeat steps 2-3 indefinitely
  5. Refresh page
  6. Login and get directed to the homepage
  7. Click any button that requires a new webpage to appear
  8. Get redirected back to the base URL
  9. Login and get directed to requested page

Expected behavior I expect to log in 1 time per session and be able to use the software

Leantime Version Which Leantime version are you using

Server Docker, reverse proxied through Traefik.

PHP / MySQL Version 10.11.6-MariaDB PHP 8.1.28

marcelfolaron commented 2 months ago

Are you using an OIDC provider? I went to the URL and the login screen seems to be through Authelia. We haven't tested logins via Authelia but it sounds like an oidc config. I can't reproduce this issue with the standard login methods. The %2F is a urlencoded "/". Is that in your config anywhere?

JustEnoughDucks commented 2 months ago

No, there is an authelia front-end 2FA for the entire site. Anything after the user is authenticated can log into service-per-service through their own provider.

My compose looks like this:

services:
  leantime:
    image: leantime/leantime:latest
    container_name: leantime
    restart: unless-stopped
    secrets:
      - lean-db-password
      - lean-session-password
    security_opt:
      - no-new-privileges:true
    environment:
      LEAN_APP_URL: 'https://my.domain.here'                    # Only needed for subdirectory setup; protocol (http or https) and base URL , trailing slash not needed
      LEAN_SITENAME: 'Leantime'                                         # Name of your site, can be changed later
      LEAN_DB_HOST: 'mariadb:3306'                                    # Database host, derived from container_name in leantime_db container
      LEAN_DB_USER: 'leantime'
      LEAN_DB_PASSWORD_FILE: /run/secrets/lean-db-password
      LEAN_DB_DATABASE: 'leantime'
      LEAN_DEFAULT_TIMEZONE: $TZ                         # Set default server timezone
      LEAN_SESSION_PASSWORD_FILE: /run/secrets/lean-session-password         # Salting sessions. Replace with a strong password
      LEAN_SESSION_EXPIRATION: 28800                                    # How many seconds after inactivity should we logout?  28800seconds = 8hours
      PUID: $PUID
      PGID: $PGID
      TZ: $TZ

    volumes:
      - $USERDIR/dockerconfig/leantime/public_userfiles:/var/www/html/public/userfiles
      - $USERDIR/dockerconfig/leantime/userfiles:/var/www/html/userfiles
    ports:
      - "8089:80"                                                       # The port to expose and access Leantime
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=web"
      ## HTTP Routers
      - "traefik.http.routers.leantime-rtr.entrypoints=https"
      - "traefik.http.routers.leantime-rtr.rule=Host(`manage.$DOMAINNAME`)"
      - "traefik.http.routers.leantime-rtr.tls=true"
      ## Middlewares
      - "traefik.http.routers.leantime-rtr.middlewares=chain-authelia@file"
#     - "traefik.http.routers.leantime-rtr.middlewares=chain-no-auth@file"
      ## HTTP Services
      - "traefik.http.routers.leantime-rtr.service=leantime-svc"
      - "traefik.http.services.leantime-svc.loadbalancer.server.port=80"
    networks:
      web:
        ipv4_address: 192.168.90.28

volumes:
  userfiles:
  public_userfiles:

secrets:
  lean-db-password:
    file: $SECRETSDIR/LEAN_DB_PASSWORD
  lean-session-password:
    file: $SECRETSDIR/LEAN_SESSION_PASSWORD

networks:
  web:
    external: true

Everything has worked for close to 2 years until the most recent update to 3.1.4 from 3.0.7 I believe it was.

JustEnoughDucks commented 2 months ago

I have narrowed it down, because this is quite a bad issue.

The problem begins on 3.1.2. 3.1.1 works perfectly.

I don't know what commit broke things, but maybe it has to do with the middleware improvements that caused a bug somewhere?

pablopoo commented 2 months ago

Same issue here. Running 3.1.1 ok. Tested 3.1.4 and got a redirect loop with OIDC login. Noticed that with 3.1.4 my session id keeps changing. With 3.1.1 stay the same, must be by the changes on app/Core/Session.php

Could be that the session ID is regenerated before processing the SSO postback redirect? so the app lost the context and don't know what to do with the IdP response?

Zomphie commented 1 month ago

I too am having this same issue. I will be looking to install 3.1.1 and give it a go. Thank you @pablopoo.

Update: Version 3.1.1 fixed the issue. For anybody who has this issue, stick to 3.1.1 and you should be fine.

goapunk commented 1 month ago

same issue here as well

gloriafolaron commented 1 month ago

We've been looking into this on our side and working through the issue -- but we're finding it's not happening consistently across set ups but can't pin down exactly what the difference is.

Could you all share your set ups? Hoping there's some better insight into this.

We have a large release pending (if you're in our Discord, there was a recent post asking for reviews if you have time or can help!) -- having some more info might help us get this one better cleared.

pablopoo commented 1 month ago

We've been looking into this on our side and working through the issue -- but we're finding it's not happening consistently across set ups but can't pin down exactly what the difference is.

Could you all share your set ups? Hoping there's some better insight into this.

We have a large release pending (if you're in our Discord, there was a recent post asking for reviews if you have time or can help!) -- having some more info might help us get this one better cleared.

Hi Gloria!

I would start looking for the conditions of session regeneration. I noticed that my session id was constantly changing. Could be a rule in the code that reload the session if the user is not logged in. Could be the page that does the redirect to the IdP or some call to another resource on the site in that action that triggers the session regeneration.

I could try to debug it on the weekend.

Br. Pablo

marcelfolaron commented 1 month ago

Hey, I am replacing our session manager with Laravel's right now. A PR is open.

Now the reason why it would regenerate is an inconsistent server_name or client ip we are using both to prevent session hijacking. Are you behind a proxy?

pablopoo commented 1 month ago

Hey, I am replacing our session manager with Laravel's right now. A PR is open.

Now the reason why it would regenerate is an inconsistent server_name or client ip we are using both to prevent session hijacking. Are you behind a proxy?

Yes, that must be the reason. Here behind traefik and cloudflare.

JustEnoughDucks commented 1 month ago

I am also behind a cloudflare proxy -> traefik reverse proxy -> Authelia 2fa middleware -> leantime.

goapunk commented 1 month ago

same, I'm behind a reverse proxy (nginx)

marcelfolaron commented 1 month ago

So Leantime expects either HTTP_HOST or SERVER_NAME (+ IP address) for the session to be identified and tied to a user.

self::get_client_ip() . $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME']

Can you add those to your header forwarding rules?

On Wed, Jun 19, 2024 at 10:31 AM Julian Dehm @.***> wrote:

same, I'm behind a reverse proxy (nginx)

— Reply to this email directly, view it on GitHub https://github.com/Leantime/leantime/issues/2504#issuecomment-2178861632, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALG4EFSA3FZTIJZM6THR4Z3ZIGI23AVCNFSM6AAAAABHMT4XZ2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNZYHA3DCNRTGI . You are receiving this because you commented.Message ID: @.***>

goapunk commented 1 month ago

@marcelfolaron They should already be set, I will double check and add some logging to find out the actual values. Maybe they get lost by the apache in the docker image? At least from a brief glance I don't see them being passed

goapunk commented 1 month ago

Ok, it works when I stop listening for ipv6 on the intermediate reverse proxy (the chain is reverse proxy -> reverse proxy -> docker), you can also see that get_client_ip() hops between ipv6 and ipv4 (for the proxy ip) which causes the session to invalidate I guess?

afdhal395 commented 1 month ago

I am here from the Discord channel.

My intended setup is to use Cloudflare Proxy -> Traefik -> Leantime Container.

Here is my summary of investigating: I turned off Cloudflare Cache before proceeding with the steps below.

  1. Cloudflare DNS Proxy turned off & Traefik turned off (direct TCP access)

    • I can use Leantime with no issue.
  2. Cloudflare DNS Proxy turned off & Traefik turned on (only using Traefik proxy)

    • I can use Leantime with no issue.
  3. Cloudflare DNS Proxy turned on & Traefik turned on (fully behind reverse proxy) Disabled Cloudflare Always Use HTTPS. Disabled Cloudflare Automatic HTTPS Rewrites. Going through plain HTTP, not HTTPS.

    • I got redirected to login page again and again on navigating Leantime. Attached here is the console output.

Screenshot 2024-06-25 034027

I am not sure if Cloudflare Proxy causing some issue here. Would be great if others can replicate the the results as I am. Or even on other scenario that I am not thinking of.

afdhal395 commented 1 month ago

After further troubleshooting, I cannot succeed using reverse proxy chaining (Cloudflare -> Traefik -> Leantime) while Cloudflare proxy is enabled (orange-cloud icon in DNS settings). I need to disable the orange-cloud Cloudflare icon for it to work. I tried with IPv6 Compatibility turned off, but no success. My Traefik setup only listening to ipv4 only.

As for now, my working setup is Traefik -> Leantime as the Cloudflare orange-cloud is disabled.