causefx / Organizr

HTPC/Homelab Services Organizer - Written in PHP
GNU General Public License v3.0
5.12k stars 289 forks source link

server auth redirect for traefik #1240

Closed calmcacil closed 4 years ago

calmcacil commented 5 years ago
Organizr Version: V2 Official Docker
Branch: Master
WebServer: nginx
Operating System: Debian10/docker

Problem Description:

Its not as much a problem as it is a request for tweaks. Currently if you try to access any of your containers behind treafik forward auth using organizr as the api (as per the documentation) you will be meet with a 401 error if you are not logged in, which is fine but I was wondering if we could have a way to redirect it in case of a 401 error to the login page instead of just showing a flat error. This is the behavior using traefik-forward-auth would have, and it would be nice to have for organizr as a server auth provider as well. Potentially by simply being able to add ?loginredirect=loginurl at the end of the case of a 401 error for said page.


Reproduction Steps:

Access any traefik enabled container with organizr api as the auth provider without being logged in.


tronyx commented 5 years ago

If you have the custom error pages configured correctly that is the default behavior after you click the "OK" button on the 401 error page.

error_page 401 https://domain.com/?error=$status&return=$scheme://$server_name$request_uri; error_page 400 402 403 404 405 408 502 503 504 https://domain.com/?error=$status; error_page 500 https://domain.com/?error=401&return=$scheme://$server_name$request_uri;

calmcacil commented 5 years ago

Custom errors are working fine, and such on the organizr container, but when trying to access any of the other containers using organizr as a forward auth, it just shows the standard google chrome 401 error.

calmcacil commented 5 years ago

For reference I'm testing using the example from the docs. https://docs.organizr.app/books/setup-features/page/serverauth

HalianElf commented 5 years ago

Looks like you need to set up error pages too: https://docs.traefik.io/configuration/commons/#custom-error-pages

calmcacil commented 5 years ago

I tried that already, no success. also if you access the api trough the link manually when not logged in it does not show the 401 error page so it seems 401 error pages are not working, 404 and the likes work as expected but 401 from the api shows the generic browser 401.

calmcacil commented 5 years ago

Did some further testing, and i got it to the point where it tries to show the login/custom error page, but instead shows a large blank white page with ` An Error Occured Close Error

Navigation `

If i were to guess, its trying to display proxy the error and login page, rather than redirecting to it.

causefx commented 5 years ago

Paste your config files

h-wb commented 5 years ago

Hello, I'm quite interested to do that as well, but I really don't know how to do it with traefik. I don't have custom error pages either, I tried different things but as calmcacil it just shows the standard error.

By the way I'm using Traefik 2, so from what I read, we're supposed to use these labels now :

      - "traefik.http.middlewares.test.errors.status=400-599"
      - "traefik.http.middlewares.test.errors.service=organizr"
      - "traefik.http.middlewares.test.errors.query=/{status}.html"

https://docs.traefik.io/middlewares/errorpages/

HalianElf commented 5 years ago

I found this which looks like you can set this in the traefik config itself. Maybe try setting it there? Since it's all subdomains the error pages need to know what the main domain/subdomain is to go to for the error pages since /?error={status} isn't going to exist on anything but Organizr so the middleware probably isn't the right place to do it thinking further on it. https://www.reddit.com/r/Traefik/comments/89q2ln/traefik_custom_error_page_with_docker_swarm/

h-wb commented 5 years ago

I tried in the TOML but it doesn't change anything. For traefik 2, the only way to get custom error pages is trough middlewares, cause that's the way it works now (I think so) but you can put the middleware in the toml or in the docker compose. What I tried is to put the middleware in organizr's labels and call this middleware from each service, but it doesn't work either.

romancin commented 5 years ago

Did some further testing, and i got it to the point where it tries to show the login/custom error page, but instead shows a large blank white page with ` An Error Occured Close Error

Navigation `

If i were to guess, its trying to display proxy the error and login page, rather than redirecting to it.

Same error here, this is the response: image

Traefik is catching 401 correctly when accessing the pathprefix for the service:

... time="2019-09-23T20:06:52Z" level=error msg="Caught HTTP Status Code 401, returning error page" time="2019-09-23T20:06:52Z" level=error msg="Caught HTTP Status Code 401, returning error page" time="2019-09-23T20:06:52Z" level=error msg="Caught HTTP Status Code 401, returning error page" time="2019-09-23T20:06:52Z" level=error msg="Caught HTTP Status Code 401, returning error page" time="2019-09-23T20:06:53Z" level=error msg="Caught HTTP Status Code 401, returning error page"

Configuration: labels:

NebulousAnchor commented 4 years ago

+1 for this. I can currently get the same as calmcacil. I can also get organizr to try and load, but I just get a spinning organizr loader.

By using an external address as my forwardauth, vs http://organizr, I can get it to catch the page and serve it but it won't fully load and therefore also won't redirect.

Rules.toml

[http.middlewares] [http.middlewares.errorpage] [http.middlewares.errorpage.errors] status = ["401","500-599"] service = "organizr@docker" query = "/?error={status}&redirect=https://mydomain.com" [http.middlewares.auth] [http.middlewares.auth.forwardAuth] address = "https://mydomain.com/api/?v1/auth&group=1" trustForwardHeader = true authResponseHeaders = ["X-Forwarded-User", "X-Auth-User", "X-Secret", "cookie"] [http.middlewares.secure-headers] [http.middlewares.secure-headers.headers] customFrameOptionsValue = "allow-from media.mydomain.com" contentSecurityPolicy = "upgrade-insecure-requests, frame-ancestors media.mydomain.com" referrerPolicy = "strict-origin-when-cross-origin" SSLRedirect = true STSSeconds = 315360000 browserXSSFilter = true contentTypeNosniff = true forceSTSHeader = true SSLHost = "media.mydomain.com" STSIncludeSubdomains = true STSPreload = true frameDeny = false [http.middlewares.secured] [http.middlewares.secured.chain] middlewares = ["auth", "errorpage", "secure-headers"]

Part of Compose-Stack.yml

organizr: hostname: organizr image: organizrtools/organizr-v2:latest volumes:

radarr: image: linuxserver/radarr:latest hostname: radarr volumes:

h-wb commented 4 years ago

Any news on this ?

ddimick commented 4 years ago

There may be a misunderstanding of how Traefik ForwardAuth works and why a code change to Organizr is required to enable the desired behavior. This can't be done just messing around with error pages. It can be done with error pages, just not very well.

https://docs.traefik.io/v2.0/middlewares/forwardauth/

If the service response code is 2XX, access is granted and the original request is performed. Otherwise, the response from the authentication server is returned.

If Organizr would add a Location header along with the 401 that redirects to the main/landing page, everything would work as expected. I tested this concept in the auth() function of organizr-function.php and it works. The example below isn't the right way to do it, just a proof of concept.

Replace:

!$debug ? exit(http_response_code(401)) : die("$userInfo Not Authorized");

With:

http_response_code(401);
header('Location: https://your.server/organizr/');
exit();

Edit: upon further reflection this could be done with Traefik errorpage redirects, but you would also have to modify Organizr's index page to use absolute URLs to load resources. It's far easier to modify the auth function to redirect.

ddimick commented 4 years ago

Outside the scope of Organizr but, as a workaround, here's a PHP error page I whipped up that can be used while I think up a better way.

<?php
/**
 * Errorpage handler for Traefik that redirects 401/403. Example Traefik labels:
 * 
 * - "traefik.http.routers.<organizr router>.middlewares=<errorpage middleware name>"
 * - "traefik.http.middlewares.<errorpage middleware name>.errors.status=400-401, 403-404, 500-503"
 * - "traefik.http.middlewares.<errorpage middleware name>.errors.service=<traefik errorpage service>"
 * - "traefik.http.middlewares.<errorpage middleware name>.errors.query=/?{status}"
 * 
 * Redirects are being done with Javascript as location headers aren't making it through to the client.
 */

 if (preg_match('/^\d{3}$/', $_SERVER['QUERY_STRING'])) { // only accept 3-digit numbers in the query
  switch ($_SERVER['QUERY_STRING']) {
    case "400":
      $error_number = $_SERVER['QUERY_STRING'];
      $error_title = "Bad Request";
      $error_text = "The server cannot process the request.";
    break;

    case "401":
      if ($_SERVER['HTTP_X_FORWARDED_PROTO'] && $_SERVER['HTTP_X_FORWARDED_HOST']) {
        $redirect_url = $_SERVER['HTTP_X_FORWARDED_PROTO'] . '://' . $_SERVER['HTTP_X_FORWARDED_HOST'];
        exit('<script type="text/javascript">window.location = "' . $redirect_url . '";</script>');
      } else {
        $error_number = $_SERVER['QUERY_STRING'];
        $error_title = "Unauthorized";
        $error_text = "Authorization is required.";        
      }
    break;

    case "403":
      if ($_SERVER['HTTP_X_FORWARDED_PROTO'] && $_SERVER['HTTP_X_FORWARDED_HOST']) {
        $redirect_url = $_SERVER['HTTP_X_FORWARDED_PROTO'] . '://' . $_SERVER['HTTP_X_FORWARDED_HOST'];
        exit('<script type="text/javascript">window.location = "' . $redirect_url . '";</script>');
      } else {
        $error_number = $_SERVER['QUERY_STRING'];
        $error_title = "Forbidden";
        $error_text = "Access is forbidden.";        
      }
    break;

    case "404":
      $error_number = $_SERVER['QUERY_STRING'];
      $error_title = "Not Found";
      $error_text = "The requested resource could not be found.";
    break;

    case "500":
      $error_number = $_SERVER['QUERY_STRING'];
      $error_title = "Internal Server Error";
      $error_text = "An unexpected condition was encountered.";
    break;

    case "501":
      $error_number = $_SERVER['QUERY_STRING'];
      $error_title = "Not Implemented";
      $error_text = "THe server did not recognize the request method.";
    break;

    case "502":
      $error_number = $_SERVER['QUERY_STRING'];
      $error_title = "Bad Gateway";
      $error_text = "Received an invalid response from the upstream server.";
    break;

    case "503":
      $error_number = $_SERVER['QUERY_STRING'];
      $error_title = "Service Unavailable";
      $error_text = "The server is currently unavailable.";
    break;

    default:
      $error_number = "?";
      $error_title = "Unknown Error";
      $error_text = "There was an error, but we don't know how to describe it.";
  }
 } else {
  exit(); // exit silently if invalid or missing HTTP status code.
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Modified from Simple HttpErrorPages | MIT License | https://github.com/AndiDittrich/HttpErrorPages -->
    <meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Error <?=$error_number?> - <?=$error_title?></title>
    <style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */body,html{width:100%;height:100%;background-color:#21232a}body{color:#fff;text-align:center;text-shadow:0 2px 4px rgba(0,0,0,.5);padding:0;min-height:100%;-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,.8);box-shadow:inset 0 0 100px rgba(0,0,0,.8);display:table;font-family:"Open Sans",Arial,sans-serif}h1{font-family:inherit;font-weight:500;line-height:1.1;color:inherit;font-size:36px}h1 small{font-size:68%;font-weight:400;line-height:1;color:#777}a{text-decoration:none;color:#fff;font-size:inherit;border-bottom:dotted 1px #707070}.lead{color:silver;font-size:21px;line-height:1.4}.cover{display:table-cell;vertical-align:middle;padding:0 20px}footer{position:fixed;width:100%;height:40px;left:0;bottom:0;color:#a0a0a0;font-size:14px}</style>
</head>
<body>
    <div class="cover"><h1><?=$error_title?> <small>Error <?=$error_number?></small></h1><p class="lead"><?=$error_text?></p></div>
    <footer><p>&nbsp;</p></footer>
</body>
</html>
ddimick commented 4 years ago

PR #1314

h-wb commented 4 years ago

Hello @ddimick Thanks for your work ! Your first solution is working (since the url is hard-coded) but unfortunately, your PR is not working for me, I didn't try much but I guess it has something to do with the $redirect_header (as my organizr domain name is just : https://mydomain.com or https://organizr.mydomain.com and not https://mydomain/organizr/).

ddimick commented 4 years ago

Is your Traefik instance configured to use a FQDN/externally accessible domain/URL for your forwardauth.address?

Another option might be to add a user-configurable field for the redirect target within Settings, but I was hoping to keep it simple.

causefx commented 4 years ago

I can cook something up for you guys.

Sent from my iPhone

On Feb 22, 2020, at 6:19 PM, Doug Dimick notifications@github.com wrote:

 Is your Traefik instance configured to use a FQDN/externally accessible domain/URL for your forwardauth.address?

Another option might be to add a user-configurable field for the redirect target within Settings, but I was hoping to keep it simple.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

h-wb commented 4 years ago

Is your Traefik instance configured to use a FQDN/externally accessible domain/URL for your forwardauth.address?

Another option might be to add a user-configurable field for the redirect target within Settings, but I was hoping to keep it simple.

Yes it is ! I wanted to see what was the value of my $redirect_header to see if there was an issue but I'm not really into PHP aha.

I can cook something up for you guys.

Thanks !

causefx commented 4 years ago

@ddimick @h-wb does traefik always set this header as traefix 100% of the time? HTTP_X_FORWARDED_SERVER

ddimick commented 4 years ago

No, I made an error in that assumption. It sets it to the hostname of the system Traefik is running under.

causefx commented 4 years ago

Okay I will add a toggle in settings

causefx commented 4 years ago

If any of you are running the dev branch, you can enable the toggle to test that.

ddimick commented 4 years ago

Working great for me!

causefx commented 4 years ago

awesome! lets see if we can get the go ahead from @h-wb

h-wb commented 4 years ago

Working great for me too ! Thanks !

causefx commented 4 years ago

Awesome! I'll push this to master at the end of the week!

a-nunes commented 4 years ago

I don't know if I'm doing something wrong, but mine just works if I use my hardcoded domain. If I use my docker on forwardauth, it just redirects me to http://organizr/

Is it right or am I doing anything wrong?

causefx commented 4 years ago

Is your Traefik instance configured to use a FQDN/externally accessible domain/URL for your forwardauth.address?

Judging by this comment it has to the domain

romancin commented 4 years ago

Please, can someone paste here docker-compose file are you using? I am trying to configure this but cannot make expose /api working, so authentication doesn't work using external domain.

ddimick commented 4 years ago

This might not be the best example but hopefully it helps at little.

networks:
  traefik:
  traefik-socket:
    internal: true

services:
  traefik:
    container_name: traefik
    hostname: traefik
    image: localhost:5000/local/traefik
    restart: always     

    environment:
      - TZ
      - TRAEFIK_ENTRYPOINTS_HTTP_ADDRESS=:8080
      - TRAEFIK_PROVIDERS_DOCKER_ENDPOINT=tcp://traefik-socket:2375
      - TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT=false
      - TRAEFIK_PROVIDERS_DOCKER_NETWORK=${COMPOSE_PROJECT_NAME}_traefik
      - TRAEFIK_PROVIDERS_DOCKER_DEFAULTRULE=(Host(`www.${SUBDOMAIN}.${DOMAIN}`) || Host(`${SUBDOMAIN}.${DOMAIN}`)) && PathPrefix(`/{{ trimSuffix "-docker-stack" .Name }}`)
      - TRAEFIK_API=true
      - TRAEFIK_PING=true
      - TRAEFIK_PING_ENTRYPOINT=http
      - TRAEFIK_PING_MANUALROUTING=true

    labels:
      - "traefik.enable=true"

      - "traefik.http.routers.api.rule=(Host(`www.${SUBDOMAIN}.${DOMAIN}`) || Host(`${SUBDOMAIN}.${DOMAIN}`)) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
      - "traefik.http.routers.api.service=api@internal"
      - "traefik.http.routers.api.middlewares=clean-root, auth"

      - "traefik.http.routers.ping.rule=PathPrefix(`/ping`)"
      - "traefik.http.routers.ping.service=ping@internal"
      - "traefik.http.routers.ping.middlewares=ipwhitelist-ping"

      - "traefik.http.middlewares.clean-root.redirectregex.regex=^http(?:s)?://${SUBDOMAIN}\\.${DOMAIN}/(.*)"
      - "traefik.http.middlewares.clean-root.redirectregex.replacement=https://www.${SUBDOMAIN}.${DOMAIN}/$${1}"

      - "traefik.http.middlewares.auth.forwardauth.address=https://www.${SUBDOMAIN}.${DOMAIN}/organizr/api/?v1/auth&group=1"

      - "traefik.http.middlewares.ipwhitelist.ipwhitelist.sourcerange=x.x.x.x/xx"
      - "traefik.http.middlewares.ipwhitelist.ipwhitelist.ipstrategy.excludedips=x.x.x.x"

      - "traefik.http.middlewares.ipwhitelist-ping.ipwhitelist.sourcerange=x.x.x.x/xx, x.x.x.x/xx"

    ports:
      - 80:8080/tcp

    networks:
      - default
      - traefik
      - traefik-socket

    depends_on:
      - traefik-socket
      - traefik-errorpages

  traefik-socket:
    container_name: traefik-socket
    hostname: traefik-socket
    image: tecnativa/docker-socket-proxy
    restart: always

    environment:
      - CONTAINERS=1

    networks:
      - traefik-socket

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro

  traefik-errorpages:
    container_name: traefik-errorpages
    hostname: traefik-errorpages
    image: linuxserver/nginx
    restart: always

    environment:
      - TZ
      - PUID=${USER_UID}
      - PGID=${USER_GID}

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik-errorpages.middlewares=errorpages"
      - "traefik.http.middlewares.errorpages.errors.status=400-401, 403-404, 500-503, 520-521"
      - "traefik.http.middlewares.errorpages.errors.service=traefik-errorpages-${COMPOSE_PROJECT_NAME}"
      - "traefik.http.middlewares.errorpages.errors.query=/?{status}"
      - "com.centurylinklabs.watchtower.enable=true"

    networks:
      - traefik

    volumes:
      - ${PROJECT_PATH}/traefik/volumes/errorpages:/config/www

  organizr:
    container_name: organizr
    hostname: www.${SUBDOMAIN}.${DOMAIN}
    image: organizrtools/organizr-v2
    restart: always

    environment:
      - TZ
      - PUID=${USER_UID}
      - PGID=${USER_GID}

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.organizr.rule=(Host(`www.${SUBDOMAIN}.${DOMAIN}`) || Host(`${SUBDOMAIN}.${DOMAIN}`)) && (PathPrefix(`/`) || PathPrefix(`/organizr`))"
      - "traefik.http.routers.organizr.middlewares=organizr-redirect-root, organizr-stripprefix, errorpages"
      - "traefik.http.routers.organizr.priority=1"
      - "traefik.http.middlewares.organizr-redirect-root.redirectregex.regex=^http(?:s)?://(?:www\\.)?${SUBDOMAIN}\\.${DOMAIN}/$$"
      - "traefik.http.middlewares.organizr-redirect-root.redirectregex.replacement=https://www.${SUBDOMAIN}.${DOMAIN}/organizr/"
      - "traefik.http.middlewares.organizr-stripprefix.stripprefix.prefixes=/organizr"
      - "com.centurylinklabs.watchtower.enable=true"

    networks:
      - traefik

    volumes:
      - ${PROJECT_PATH}/organizr/volumes:/config
romancin commented 4 years ago

Thank you very much for the example, but It seems you aren't using organizr authentication.

ddimick commented 4 years ago

I am, I just neglected to include an example of service using it. Apologies. The auth middleware being used here refers to where I defined it under the traefik service.

version: "3.7"

services:
  nzbget:
    container_name: nzbget
    hostname: nzbget
    image: linuxserver/nzbget
    restart: always

    environment:
      - TZ
      - PUID=${USER_UID}
      - PGID=${USER_GID}

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nzbget.middlewares=clean-root, auth"
      - "com.centurylinklabs.watchtower.enable=true"

    networks:
      - traefik

    volumes:
      - ${PROJECT_PATH}/nzbget/volumes:/config
      - /mnt/system0/downloads/nzbs:/downloads
undaunt commented 4 years ago

@ddimick Thanks for your compose!! - going to use it to help get myself off Traefik v1 to v2, improve the security on watchtower et. al with docker-socket-proxy, and get Organizr auth going for (ideally) subdomain https.

Question though, could you also share a clean version of your Traefik v2 toml/yaml config?

ddimick commented 4 years ago

I don't use a toml/yaml file to config Traefik. Everything is set using environment variables in the compose file.

romancin commented 4 years ago

I am, I just neglected to include an example of service using it. Apologies. The auth middleware being used here refers to where I defined it under the traefik service.

version: "3.7"

services:
  nzbget:
    container_name: nzbget
    hostname: nzbget
    image: linuxserver/nzbget
    restart: always

    environment:
      - TZ
      - PUID=${USER_UID}
      - PGID=${USER_GID}

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nzbget.middlewares=clean-root, auth"
      - "com.centurylinklabs.watchtower.enable=true"

    networks:
      - traefik

    volumes:
      - ${PROJECT_PATH}/nzbget/volumes:/config
      - /mnt/system0/downloads/nzbs:/downloads

Thank you very much! I am trying to understand your case to adapt it to me. Let's suppose the domain mydomain.com.

In www.mydomain.com or www.mydomain.com/organizr you have organizr accesible right? And the redirect makes all requests go to www.mydomain.com/organizr/ including api/ authentication?

ddimick commented 4 years ago

Yes, correct. www.mydomain.com/ redirects to www.mydomain.com/organizr. The organizr authentication mechanism is exposed at www.mydomain.com/organizr/api/.

Other services are served up like www.mydomain.com/otherservice/, like www.mydomain.com/nzbget/.

Setting Traefik priority 1 for organizr is crucial if you're using it this way.

romancin commented 4 years ago

OMG, it's working! Thank you very much! :)

What about clean-root? What does it do?

ddimick commented 4 years ago

clean-root just redirects http://mydomain.com/whatever or https://mydomain.com/whatever to https://www.mydomain.com/whatever

romancin commented 4 years ago

Ok, got it ! Thank you!

a-nunes commented 4 years ago

Yes, correct. www.mydomain.com/ redirects to www.mydomain.com/organizr. The organizr authentication mechanism is exposed at www.mydomain.com/organizr/api/.

Other services are served up like www.mydomain.com/otherservice/, like www.mydomain.com/nzbget/.

Setting Traefik priority 1 for organizr is crucial if you're using it this way.

But when you go to www.mydomain.com/nzbget/ it redirects you to www.mydomain.com/organizr/ in order to make your login and join the organizr? Or just use it as Auth system, once you put or login/password it redirects you again to www.mydomain.com/nzbget/?

What I'm trying to do is use it just as a Auth layer... if someone goes to subdomain, redirects to main domain to authenticate, after auth -> redirects again to subdomain, instead of join on Organizr main page.

ddimick commented 4 years ago

But when you go to www.mydomain.com/nzbget/ it redirects you to www.mydomain.com/organizr/ in order to make your login and join the organizr?

Yup. I agree that it would be nice if you could auth and then redirect to the originally requested URL. Maybe there is a clever way of using Traefik to do something like set a header with the original URL and then use it to redirect again after auth or something along those likes, but I haven't investigated it.

a-nunes commented 4 years ago

@causefx any ideia that could help us?

causefx commented 4 years ago

We do that with Nginx - if 401 it sends to Organizr 401 error page to login - once logged in it forwards you back to the requested page. No clue how to setup error pages on Traefik...

https://docs.organizr.app/books/setup-features/page/custom-error-pages

We make use of the return=$request_uri on the url... hopefully you can do the same.

ddimick commented 4 years ago

Traefik does not appear to be able to pass the request URI in their custom error page implementation.

https://docs.traefik.io/middlewares/errorpages/

causefx commented 4 years ago

Try opening an issue on GH and asking them to add it - they are really cool.

ddimick commented 4 years ago

Looks like there is an issue opened for it already at https://github.com/containous/traefik/issues/3420.

Gibletron commented 4 years ago

I have been having a lot of issues getting Traefik v2 working with Organizr Forward Auth. Even with the above examples I haven't been able to pinpoint my exact issue.

I use the following middleware:

      [HTTP.Middlewares.org-coadmin.ForwardAuth]
        Address = "https://organizr.mydomain.com/api/?v1/auth&group=1"

I have also tried this with the following additions:

        TrustForwardHeader = true
        AuthResponseHeaders = ["X-WebAuth-User"]
        [HTTP.Middlewares.org-coadmin.ForwardAuth.TLS]
          InsecureSkipVerify = true

And a container using the middleware:

        traefik.http.routers.droppy-ext.entryPoints: "https"
        traefik.http.routers.droppy-ext.tls: "true"
        traefik.http.routers.droppy-ext.rule: "Host(`droppy.mydomain.com`)"
        traefik.http.routers.droppy-ext.service: "droppy"
        traefik.http.routers.droppy-ext.middlewares: "org-admin@file, 401@file"

When I am not logged in to orgnizr and go to droppy.mydomain.com I get a "cannot resolve" because it tries to go to https://organizr/ When I am logged in to Organizr, it sends me to droppy without an issue.

I have enable the traefik option in orgnizr, but suspect it has nothing to do with the issue I'm facing. In the past I used traefik error pages to forward to a simple html page which automatically redirected to the organizr login page, not pretty but worked. I thought this was still happening and an issue with the error middelware, but if I change the error middelware to a completly different container, I still get the "cannot resolve" issue for https://organizr/ so it seems the ForwardAuth is already breaking.

Could someone who has this working help me out and maybe check out my toml files together?

a-nunes commented 4 years ago

I've the same issue.

https://github.com/causefx/Organizr/issues/1240#issuecomment-600076171

Read the reply right below this my answer.