summaryrefslogtreecommitdiff
path: root/internal/handlers/handler_authz_impl_forwardauth_test.go
diff options
context:
space:
mode:
authorJames Elliott <james-d-elliott@users.noreply.github.com>2023-01-25 20:36:40 +1100
committerGitHub <noreply@github.com>2023-01-25 20:36:40 +1100
commit65705a646dfd31e4477af3ffb35c584eb49346a4 (patch)
tree882b5df73348c5fc6471e57ef6787c4b04cb68f4 /internal/handlers/handler_authz_impl_forwardauth_test.go
parent78064dec2e9b48308b71ff8862b27e6f8ded5d56 (diff)
feat(server): customizable authz endpoints (#4296)
This allows users to customize the authz endpoints. Closes #2753, Fixes #3716 Co-authored-by: Amir Zarrinkafsh <nightah@me.com>
Diffstat (limited to 'internal/handlers/handler_authz_impl_forwardauth_test.go')
-rw-r--r--internal/handlers/handler_authz_impl_forwardauth_test.go610
1 files changed, 610 insertions, 0 deletions
diff --git a/internal/handlers/handler_authz_impl_forwardauth_test.go b/internal/handlers/handler_authz_impl_forwardauth_test.go
new file mode 100644
index 000000000..d7ea3baab
--- /dev/null
+++ b/internal/handlers/handler_authz_impl_forwardauth_test.go
@@ -0,0 +1,610 @@
+package handlers
+
+import (
+ "fmt"
+ "net/url"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/suite"
+ "github.com/valyala/fasthttp"
+
+ "github.com/authelia/authelia/v4/internal/authorization"
+ "github.com/authelia/authelia/v4/internal/middlewares"
+ "github.com/authelia/authelia/v4/internal/mocks"
+ "github.com/authelia/authelia/v4/internal/session"
+)
+
+func TestRunForwardAuthAuthzSuite(t *testing.T) {
+ suite.Run(t, NewForwardAuthAuthzSuite())
+}
+
+func NewForwardAuthAuthzSuite() *ForwardAuthAuthzSuite {
+ return &ForwardAuthAuthzSuite{
+ AuthzSuite: &AuthzSuite{
+ implementation: AuthzImplForwardAuth,
+ setRequest: setRequestForwardAuth,
+ },
+ }
+}
+
+type ForwardAuthAuthzSuite struct {
+ *AuthzSuite
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldHandleAllMethodsDeny() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for _, pairURI := range []urlpair{
+ {s.RequireParseRequestURI("https://one-factor.example.com"), s.RequireParseRequestURI("https://auth.example.com/")},
+ {s.RequireParseRequestURI("https://one-factor.example.com/subpath"), s.RequireParseRequestURI("https://auth.example.com/")},
+ {s.RequireParseRequestURI("https://one-factor.example2.com"), s.RequireParseRequestURI("https://auth.example2.com/")},
+ {s.RequireParseRequestURI("https://one-factor.example2.com/subpath"), s.RequireParseRequestURI("https://auth.example2.com/")},
+ } {
+ t.Run(pairURI.TargetURI.String(), func(t *testing.T) {
+ expected := s.RequireParseRequestURI(pairURI.AutheliaURI.String())
+
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ s.setRequest(mock.Ctx, method, pairURI.TargetURI, true, false)
+
+ authz.Handler(mock.Ctx)
+
+ switch method {
+ case fasthttp.MethodGet, fasthttp.MethodOptions, fasthttp.MethodHead:
+ assert.Equal(t, fasthttp.StatusFound, mock.Ctx.Response.StatusCode())
+ default:
+ assert.Equal(t, fasthttp.StatusSeeOther, mock.Ctx.Response.StatusCode())
+ }
+
+ query := expected.Query()
+ query.Set(queryArgRD, pairURI.TargetURI.String())
+ query.Set(queryArgRM, method)
+ expected.RawQuery = query.Encode()
+
+ assert.Equal(t, expected.String(), string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation)))
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldHandleAllMethodsOverrideAutheliaURLDeny() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for _, pairURI := range []urlpair{
+ {s.RequireParseRequestURI("https://one-factor.example.com"), s.RequireParseRequestURI("https://auth-from-override.example.com/")},
+ {s.RequireParseRequestURI("https://one-factor.example.com/subpath"), s.RequireParseRequestURI("https://auth-from-override.example.com/")},
+ {s.RequireParseRequestURI("https://one-factor.example2.com"), s.RequireParseRequestURI("https://auth-from-override.example2.com/")},
+ {s.RequireParseRequestURI("https://one-factor.example2.com/subpath"), s.RequireParseRequestURI("https://auth-from-override.example2.com/")},
+ } {
+ t.Run(pairURI.TargetURI.String(), func(t *testing.T) {
+ expected := s.RequireParseRequestURI(pairURI.AutheliaURI.String())
+
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ mock.Ctx.RequestCtx.QueryArgs().Set("authelia_url", pairURI.AutheliaURI.String())
+ s.setRequest(mock.Ctx, method, pairURI.TargetURI, true, false)
+
+ authz.Handler(mock.Ctx)
+
+ switch method {
+ case fasthttp.MethodGet, fasthttp.MethodOptions, fasthttp.MethodHead:
+ assert.Equal(t, fasthttp.StatusFound, mock.Ctx.Response.StatusCode())
+ default:
+ assert.Equal(t, fasthttp.StatusSeeOther, mock.Ctx.Response.StatusCode())
+ }
+
+ query := expected.Query()
+ query.Set(queryArgRD, pairURI.TargetURI.String())
+ query.Set(queryArgRM, method)
+ expected.RawQuery = query.Encode()
+
+ assert.Equal(t, expected.String(), string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation)))
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldHandleAllMethodsMissingAutheliaURLDeny() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for _, targetURI := range []*url.URL{
+ s.RequireParseRequestURI("https://bypass.example.com"),
+ s.RequireParseRequestURI("https://bypass.example.com/subpath"),
+ s.RequireParseRequestURI("https://bypass.example2.com"),
+ s.RequireParseRequestURI("https://bypass.example2.com/subpath"),
+ } {
+ t.Run(targetURI.String(), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ s.setRequest(mock.Ctx, method, targetURI, true, false)
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, "", string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation)))
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldHandleAllMethodsXHRDeny() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for xname, x := range testXHR {
+ t.Run(xname, func(t *testing.T) {
+ for _, pairURI := range []urlpair{
+ {s.RequireParseRequestURI("https://one-factor.example.com"), s.RequireParseRequestURI("https://auth.example.com/")},
+ {s.RequireParseRequestURI("https://one-factor.example.com/subpath"), s.RequireParseRequestURI("https://auth.example.com/")},
+ {s.RequireParseRequestURI("https://one-factor.example2.com"), s.RequireParseRequestURI("https://auth.example2.com/")},
+ {s.RequireParseRequestURI("https://one-factor.example2.com/subpath"), s.RequireParseRequestURI("https://auth.example2.com/")},
+ } {
+ t.Run(pairURI.TargetURI.String(), func(t *testing.T) {
+ expected := s.RequireParseRequestURI(pairURI.AutheliaURI.String())
+
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ s.setRequest(mock.Ctx, method, pairURI.TargetURI, x, x)
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+
+ query := expected.Query()
+ query.Set(queryArgRD, pairURI.TargetURI.String())
+ query.Set(queryArgRM, method)
+ expected.RawQuery = query.Encode()
+
+ assert.Equal(t, expected.String(), string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation)))
+ })
+ }
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldHandleInvalidMethodCharsDeny() {
+ for _, method := range testRequestMethods {
+ method += "z"
+
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for _, targetURI := range []*url.URL{
+ s.RequireParseRequestURI("https://bypass.example.com"),
+ s.RequireParseRequestURI("https://bypass.example.com/subpath"),
+ s.RequireParseRequestURI("https://bypass.example2.com"),
+ s.RequireParseRequestURI("https://bypass.example2.com/subpath"),
+ } {
+ t.Run(targetURI.String(), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ s.setRequest(mock.Ctx, method, targetURI, true, false)
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldHandleMissingHostDeny() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ mock.Ctx.Request.Header.Set("X-Forwarded-Method", method)
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderXForwardedProto, "https")
+ mock.Ctx.Request.Header.Del(fasthttp.HeaderXForwardedHost)
+ mock.Ctx.Request.Header.Set("X-Forwarded-Uri", "/")
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderAccept, "text/html; charset=utf-8")
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldHandleAllMethodsAllow() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for _, targetURI := range []*url.URL{
+ s.RequireParseRequestURI("https://bypass.example.com"),
+ s.RequireParseRequestURI("https://bypass.example.com/subpath"),
+ s.RequireParseRequestURI("https://bypass.example2.com"),
+ s.RequireParseRequestURI("https://bypass.example2.com/subpath"),
+ } {
+ t.Run(targetURI.String(), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ s.setRequest(mock.Ctx, method, targetURI, true, false)
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusOK, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldHandleAllMethodsWithMethodsACL() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for _, methodACL := range testRequestMethods {
+ targetURI := s.RequireParseRequestURI(fmt.Sprintf("https://bypass-%s.example.com", strings.ToLower(methodACL)))
+ t.Run(targetURI.String(), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ s.setRequest(mock.Ctx, method, targetURI, true, false)
+
+ authz.Handler(mock.Ctx)
+
+ if method == methodACL {
+ assert.Equal(t, fasthttp.StatusOK, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ } else {
+ expected := s.RequireParseRequestURI("https://auth.example.com/")
+
+ switch method {
+ case fasthttp.MethodGet, fasthttp.MethodOptions, fasthttp.MethodHead:
+ assert.Equal(t, fasthttp.StatusFound, mock.Ctx.Response.StatusCode())
+ default:
+ assert.Equal(t, fasthttp.StatusSeeOther, mock.Ctx.Response.StatusCode())
+ }
+
+ query := expected.Query()
+ query.Set(queryArgRD, targetURI.String())
+ query.Set(queryArgRM, method)
+ expected.RawQuery = query.Encode()
+
+ assert.Equal(t, expected.String(), string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation)))
+ }
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldHandleAllMethodsAllowXHR() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for _, targetURI := range []*url.URL{
+ s.RequireParseRequestURI("https://bypass.example.com"),
+ s.RequireParseRequestURI("https://bypass.example.com/subpath"),
+ s.RequireParseRequestURI("https://bypass.example2.com"),
+ s.RequireParseRequestURI("https://bypass.example2.com/subpath"),
+ } {
+ t.Run(targetURI.String(), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ s.setRequest(mock.Ctx, method, targetURI, true, true)
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusOK, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldHandleInvalidURLForCVE202132637() {
+ testCases := []struct {
+ name string
+ scheme, host []byte
+ path string
+ expected int
+ }{
+ {"Should401UnauthorizedWithNullByte",
+ []byte("https"), []byte{0, 110, 111, 116, 45, 111, 110, 101, 45, 102, 97, 99, 116, 111, 114, 46, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109}, "/path-example",
+ fasthttp.StatusUnauthorized,
+ },
+ {"Should200OkWithoutNullByte",
+ []byte("https"), []byte{110, 111, 116, 45, 111, 110, 101, 45, 102, 97, 99, 116, 111, 114, 46, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109}, "/path-example",
+ fasthttp.StatusOK,
+ },
+ }
+
+ for _, tc := range testCases {
+ s.T().Run(tc.name, func(t *testing.T) {
+ for _, method := range testRequestMethods {
+ t.Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ mock.Ctx.Configuration.AccessControl.DefaultPolicy = testBypass
+ mock.Ctx.Providers.Authorizer = authorization.NewAuthorizer(&mock.Ctx.Configuration)
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ mock.Ctx.Request.Header.Set("X-Forwarded-Method", method)
+ mock.Ctx.Request.Header.SetBytesKV([]byte(fasthttp.HeaderXForwardedProto), tc.scheme)
+ mock.Ctx.Request.Header.SetBytesKV([]byte(fasthttp.HeaderXForwardedHost), tc.host)
+ mock.Ctx.Request.Header.Set("X-Forwarded-Uri", tc.path)
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderAccept, "text/html; charset=utf-8")
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, tc.expected, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldNotHandleAuthRequestAllMethodsAllow() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("OriginalMethod%s", method), func(t *testing.T) {
+ for _, targetURI := range []*url.URL{
+ s.RequireParseRequestURI("https://bypass.example.com"),
+ s.RequireParseRequestURI("https://bypass.example.com/subpath"),
+ s.RequireParseRequestURI("https://bypass.example2.com"),
+ s.RequireParseRequestURI("https://bypass.example2.com/subpath"),
+ } {
+ t.Run(targetURI.String(), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ setRequestAuthRequest(mock.Ctx, method, targetURI, true, false)
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldNotHandleAuthRequestAllMethodsWithMethodsACL() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for _, methodACL := range testRequestMethods {
+ targetURI := s.RequireParseRequestURI(fmt.Sprintf("https://bypass-%s.example.com", strings.ToLower(methodACL)))
+ t.Run(targetURI.String(), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ setRequestAuthRequest(mock.Ctx, method, targetURI, true, false)
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldNotHandleExtAuthzAllMethodsAllow() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for _, targetURI := range []*url.URL{
+ s.RequireParseRequestURI("https://bypass.example.com"),
+ s.RequireParseRequestURI("https://bypass.example.com/subpath"),
+ s.RequireParseRequestURI("https://bypass.example2.com"),
+ s.RequireParseRequestURI("https://bypass.example2.com/subpath"),
+ } {
+ t.Run(targetURI.String(), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ setRequestExtAuthz(mock.Ctx, method, targetURI, true, false)
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldNotHandleExtAuthzAllMethodsAllowXHR() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for xname, x := range testXHR {
+ t.Run(xname, func(t *testing.T) {
+ for _, targetURI := range []*url.URL{
+ s.RequireParseRequestURI("https://bypass.example.com"),
+ s.RequireParseRequestURI("https://bypass.example.com/subpath"),
+ s.RequireParseRequestURI("https://bypass.example2.com"),
+ s.RequireParseRequestURI("https://bypass.example2.com/subpath"),
+ } {
+ t.Run(targetURI.String(), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ setRequestExtAuthz(mock.Ctx, method, targetURI, x, x)
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ })
+ }
+ })
+ }
+ })
+ }
+}
+
+func (s *ForwardAuthAuthzSuite) TestShouldNotHandleExtAuthzAllMethodsWithMethodsACL() {
+ for _, method := range testRequestMethods {
+ s.T().Run(fmt.Sprintf("Method%s", method), func(t *testing.T) {
+ for _, methodACL := range testRequestMethods {
+ targetURI := s.RequireParseRequestURI(fmt.Sprintf("https://bypass-%s.example.com", strings.ToLower(methodACL)))
+ t.Run(targetURI.String(), func(t *testing.T) {
+ authz := s.Builder().Build()
+
+ mock := mocks.NewMockAutheliaCtx(t)
+
+ defer mock.Close()
+
+ for i, cookie := range mock.Ctx.Configuration.Session.Cookies {
+ mock.Ctx.Configuration.Session.Cookies[i].AutheliaURL = s.RequireParseRequestURI(fmt.Sprintf("https://auth.%s", cookie.Domain))
+ }
+
+ mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session, nil)
+
+ setRequestExtAuthz(mock.Ctx, method, targetURI, true, false)
+
+ authz.Handler(mock.Ctx)
+
+ assert.Equal(t, fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderLocation))
+ })
+ }
+ })
+ }
+}
+
+func setRequestForwardAuth(ctx *middlewares.AutheliaCtx, method string, targetURI *url.URL, accept, xhr bool) {
+ if method != "" {
+ ctx.Request.Header.Set("X-Forwarded-Method", method)
+ }
+
+ if targetURI != nil {
+ ctx.Request.Header.Set(fasthttp.HeaderXForwardedProto, targetURI.Scheme)
+ ctx.Request.Header.Set(fasthttp.HeaderXForwardedHost, targetURI.Host)
+ ctx.Request.Header.Set("X-Forwarded-Uri", targetURI.Path)
+ }
+
+ setRequestXHRValues(ctx, accept, xhr)
+}