Skip to content

Commit b3e0860

Browse files
committed
feat: Allow multiple auth-hosts
1 parent 1e42b25 commit b3e0860

File tree

7 files changed

+46
-38
lines changed

7 files changed

+46
-38
lines changed

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Start by building the application.
2-
FROM --platform=$BUILDPLATFORM golang:1.25 as build
2+
FROM --platform=$BUILDPLATFORM golang:1.25 AS build
33

44
WORKDIR /usr/src/traefik-forward-auth
5-
ENV CGO_ENABLED 0
5+
ENV CGO_ENABLED=0
66

77
COPY ./go.* ./
88
RUN --mount=type=cache,target=/go/pkg/mod \

cmd/main.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import (
44
"encoding/json"
55
"flag"
66
"fmt"
7-
"github.com/samber/lo"
8-
"github.com/sirupsen/logrus"
9-
tfa "github.com/traPtitech/traefik-forward-auth/internal"
10-
"github.com/traPtitech/traefik-forward-auth/internal/token"
117
"net/http"
128
"os"
139
"strconv"
1410
"time"
11+
12+
"github.com/samber/lo"
13+
"github.com/sirupsen/logrus"
14+
tfa "github.com/traPtitech/traefik-forward-auth/internal"
15+
"github.com/traPtitech/traefik-forward-auth/internal/token"
1516
)
1617

1718
func initConfigs(args []string) (*tfa.Config, *logrus.Logger) {

internal/auth.go

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import (
44
"crypto/rand"
55
"errors"
66
"fmt"
7-
"github.com/traPtitech/traefik-forward-auth/internal/token"
87
"net/http"
98
"net/url"
109
"strings"
1110
"time"
1211

1312
"github.com/traPtitech/traefik-forward-auth/internal/provider"
13+
"github.com/traPtitech/traefik-forward-auth/internal/token"
1414
)
1515

1616
// Request Validation
@@ -67,7 +67,7 @@ func ValidateRedirect(r *http.Request, redirect string) (*url.URL, error) {
6767
}
6868

6969
// If we're using an auth domain?
70-
if use, base := useAuthDomain(r); use {
70+
if use, base, _ := useAuthDomain(r); use {
7171
// If we are using an auth domain, they redirect must share a common
7272
// suffix with the requested redirect
7373
if !strings.HasSuffix(redirectURL.Host, base) {
@@ -97,28 +97,35 @@ func currentUrl(r *http.Request) string {
9797

9898
// Get oauth redirect uri
9999
func redirectUri(r *http.Request) string {
100-
if use, _ := useAuthDomain(r); use {
100+
if use, _, authHost := useAuthDomain(r); use {
101101
p := r.Header.Get("X-Forwarded-Proto")
102-
return fmt.Sprintf("%s://%s%s", p, config.AuthHost, config.CallbackPath)
102+
return fmt.Sprintf("%s://%s%s", p, authHost, config.CallbackPath)
103103
}
104104

105105
return fmt.Sprintf("%s%s", redirectBase(r), config.CallbackPath)
106106
}
107107

108108
// Should we use auth host + what it is
109-
func useAuthDomain(r *http.Request) (bool, string) {
110-
if config.AuthHost == "" {
111-
return false, ""
109+
func useAuthDomain(r *http.Request) (use bool, cookieHost string, authHost string) {
110+
if len(config.AuthHost) == 0 {
111+
return
112112
}
113113

114114
// Does the request match a given cookie domain?
115-
reqMatch, reqHost := config.matchCookieDomains(r.Host)
115+
reqMatch, reqCookieHost := config.matchCookieDomains(r.Host)
116+
if !reqMatch {
117+
return
118+
}
116119

117120
// Do any of the auth hosts match a cookie domain?
118-
authMatch, authHost := config.matchCookieDomains(config.AuthHost)
121+
for _, authHost := range config.AuthHost {
122+
authMatch, authCookieHost := config.matchCookieDomains(authHost)
123+
if authMatch && reqCookieHost == authCookieHost {
124+
return true, authCookieHost, authHost
125+
}
126+
}
119127

120-
// We need both to match the same domain
121-
return reqMatch && authMatch && reqHost == authHost, reqHost
128+
return
122129
}
123130

124131
// Cookie methods
@@ -250,7 +257,7 @@ func cookieDomain(requestHost string) string {
250257
// Cookie domain
251258
func csrfCookieDomain(r *http.Request) string {
252259
var host string
253-
if use, domain := useAuthDomain(r); use {
260+
if use, domain, _ := useAuthDomain(r); use {
254261
host = domain
255262
} else {
256263
host = r.Host

internal/auth_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package tfa
22

33
import (
4-
"github.com/traPtitech/traefik-forward-auth/internal/token"
54
"net/http"
65
"net/http/httptest"
76
"net/url"
87
"strings"
98
"testing"
109
"time"
1110

11+
"github.com/traPtitech/traefik-forward-auth/internal/token"
12+
1213
"github.com/stretchr/testify/assert"
1314
"github.com/stretchr/testify/require"
1415

@@ -109,7 +110,7 @@ func TestAuthValidateRedirect(t *testing.T) {
109110
//
110111
// With Auth Host
111112
//
112-
config.AuthHost = "auth.example.com"
113+
config.AuthHost = []string{"auth.example.com"}
113114
config.CookieDomains = []CookieDomain{"example.com"}
114115
errStr = "redirect host does not match any expected hosts (should match cookie domain when using auth host)"
115116

@@ -168,7 +169,7 @@ func TestRedirectUri(t *testing.T) {
168169
// With Auth URL but no matching cookie domain
169170
// - will not use auth host
170171
//
171-
config.AuthHost = "auth.example.com"
172+
config.AuthHost = []string{"auth.example.com"}
172173

173174
uri, err = url.Parse(redirectUri(r))
174175
assert.Nil(err)
@@ -179,7 +180,7 @@ func TestRedirectUri(t *testing.T) {
179180
//
180181
// With correct Auth URL + cookie domain
181182
//
182-
config.AuthHost = "auth.example.com"
183+
config.AuthHost = []string{"auth.example.com"}
183184
config.CookieDomains = []CookieDomain{"example.com"}
184185

185186
// Check url
@@ -196,7 +197,7 @@ func TestRedirectUri(t *testing.T) {
196197
r = httptest.NewRequest("GET", "https://another.com/hello", nil)
197198
r.Header.Add("X-Forwarded-Proto", "https")
198199

199-
config.AuthHost = "auth.example.com"
200+
config.AuthHost = []string{"auth.example.com"}
200201
config.CookieDomains = []CookieDomain{"example.com"}
201202

202203
// Check url
@@ -255,7 +256,7 @@ func TestAuthMakeCSRFCookie(t *testing.T) {
255256
assert.Equal("app.example.com", c.Domain)
256257

257258
// With cookie domain and auth url
258-
config.AuthHost = "auth.example.com"
259+
config.AuthHost = []string{"auth.example.com"}
259260
config.CookieDomains = []CookieDomain{"example.com"}
260261
c = MakeCSRFCookie(r, "12333378901234567890123456789012")
261262
assert.Equal("_forward_auth_csrf_123333", c.Name)

internal/config.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ type Config struct {
2525
// Allowed values: "text", "json", "pretty"
2626
LogFormat string `mapstructure:"log-format"`
2727

28-
// AuthHost defines a single host to use when returning from 3rd party auth.
29-
AuthHost string `mapstructure:"auth-host"`
28+
// AuthHost defines hosts to use when returning from 3rd party auth. Comma separated.
29+
AuthHost []string `mapstructure:"auth-host"`
3030
// CookieDomains defines domains to set auth cookie on. Comma separated.
3131
CookieDomains []CookieDomain `mapstructure:"cookie-domains"`
3232
// InsecureCookie specifies to use insecure cookies.
@@ -189,8 +189,8 @@ func (c *Config) setup() error {
189189
}
190190

191191
// Auth host check
192-
if c.AuthHost != "" {
193-
match, _ := c.matchCookieDomains(c.AuthHost)
192+
for _, authHost := range c.AuthHost {
193+
match, _ := c.matchCookieDomains(authHost)
194194
if !match {
195195
return errors.New("\"auth-host\" option must match one of \"cookie-domains\"")
196196
}

internal/config_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package tfa
22

33
import (
4-
"github.com/samber/lo"
5-
"strings"
6-
74
// "fmt"
85
"os"
6+
"strings"
97
"testing"
108
"time"
119

10+
"github.com/samber/lo"
11+
1212
"github.com/stretchr/testify/assert"
1313
"github.com/stretchr/testify/require"
1414
)
@@ -40,7 +40,7 @@ providers:
4040
assert.Equal("warn", c.LogLevel)
4141
assert.Equal("text", c.LogFormat)
4242

43-
assert.Equal("", c.AuthHost)
43+
assert.Len(c.AuthHost, 0)
4444
assert.Len(c.CookieDomains, 0)
4545
assert.False(c.InsecureCookie)
4646
assert.Equal("_forward_auth", c.CookieName)

internal/server.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@ package tfa
22

33
import (
44
"fmt"
5-
"github.com/traPtitech/traefik-forward-auth/internal/authrule"
6-
"github.com/traPtitech/traefik-forward-auth/internal/token"
7-
"github.com/traefik/traefik/v3/pkg/middlewares/requestdecorator"
85
"net/http"
96
"net/url"
107
"strings"
118

129
"github.com/samber/lo"
1310
"github.com/sirupsen/logrus"
14-
mux "github.com/traefik/traefik/v3/pkg/muxer/http"
15-
11+
"github.com/traPtitech/traefik-forward-auth/internal/authrule"
1612
"github.com/traPtitech/traefik-forward-auth/internal/provider"
13+
"github.com/traPtitech/traefik-forward-auth/internal/token"
14+
"github.com/traefik/traefik/v3/pkg/middlewares/requestdecorator"
15+
mux "github.com/traefik/traefik/v3/pkg/muxer/http"
1716
)
1817

1918
// Server contains router and handler methods
@@ -259,7 +258,7 @@ func (s *Server) AuthCallbackHandler() http.HandlerFunc {
259258

260259
// Check error
261260
authError := r.URL.Query().Get("error")
262-
if authError == "login_required" || authError == "consent_required" {
261+
if authError == "login_required" || authError == "consent_required" || authError == "interaction_required" {
263262
// Retry without the 'prompt' parameter (which was possibly 'none' or some other value)
264263
s.authRedirect(logger, w, r, p, redirect, false)
265264
return

0 commit comments

Comments
 (0)