From c0886ce9644012ec8d69f0086f6cc73cbf16c7c8 Mon Sep 17 00:00:00 2001 From: Knut Ahlers Date: Sat, 28 Dec 2019 13:12:18 +0000 Subject: [PATCH] Allow to configure anonymous access (#48) Signed-off-by: Knut Ahlers --- acl.go | 9 ++++++++- acl_test.go | 35 +++++++++++++++++++++++++++++++++++ core.go | 7 ++++++- main.go | 8 ++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/acl.go b/acl.go index de296bd..2b91e17 100644 --- a/acl.go +++ b/acl.go @@ -9,6 +9,8 @@ import ( "github.com/Luzifer/go_helpers/v2/str" ) +const groupAnonymous = "@_anonymous" + type aclRule struct { Field string `yaml:"field"` Invert bool `yaml:"invert"` @@ -148,7 +150,12 @@ func (a aclRuleSet) HasAccess(user string, groups []string, r *http.Request) acl } } - if str.StringInSlice("@_authenticated", a.Allow) && user != "" { + // Allow special group @_authenticated if any non-anonymous user is set + if str.StringInSlice("@_authenticated", a.Allow) && !str.StringInSlice(user, []string{"", "\x00"}) { + return accessAllow + } + + if str.StringInSlice(groupAnonymous, a.Allow) { return accessAllow } diff --git a/acl_test.go b/acl_test.go index 3aa9d40..5483612 100644 --- a/acl_test.go +++ b/acl_test.go @@ -77,12 +77,47 @@ func TestGroupAuthenticated(t *testing.T) { t.Error("Access was denied") } + if r.HasAccess("\x00", nil, aclTestRequest(fields)) == accessAllow { + t.Error("Access was allowed to unauth-user") + } + + if r.HasAccess("", nil, aclTestRequest(fields)) == accessAllow { + t.Error("Access was allowed to empty user") + } + r.Allow = []string{"testgroup"} if r.HasAccess(aclTestUser, aclTestGroups, aclTestRequest(fields)) == accessAllow { t.Error("Access was allowed") } } +func TestAnonymousAccess(t *testing.T) { + r := aclRuleSet{ + Rules: []aclRule{ + { + Field: "field_a", + MatchString: aclTestString("expected"), + }, + }, + Allow: []string{groupAnonymous}, + } + fields := map[string]string{ + "field_a": "expected", + } + + if r.HasAccess(aclTestUser, aclTestGroups, aclTestRequest(fields)) != accessAllow { + t.Error("Access was denied") + } + + if r.HasAccess("", nil, aclTestRequest(fields)) != accessAllow { + t.Error("Access without user was denied") + } + + if r.HasAccess("\x00", nil, aclTestRequest(fields)) != accessAllow { + t.Error("Access with special unauth-user was denied") + } +} + func TestInvertedRegexMatcher(t *testing.T) { fields := map[string]string{ "field_a": "expected", diff --git a/core.go b/core.go index b9c3c92..3b0e1b0 100644 --- a/core.go +++ b/core.go @@ -14,12 +14,17 @@ import ( ) func registerModules() { + // Start with very simple, local auth providers as they are cheap + // in their execution and therefore if they are used nginx-sso + // can process far more requests than through the other providers registerAuthenticator(simple.New(cookieStore)) + registerAuthenticator(token.New()) + + // Afterwards utilize the more expensive remove providers registerAuthenticator(crowd.New()) registerAuthenticator(ldap.New(cookieStore)) registerAuthenticator(google.New(cookieStore)) registerAuthenticator(oidc.New(cookieStore)) - registerAuthenticator(token.New()) registerAuthenticator(auth_yubikey.New(cookieStore)) registerMFAProvider(duo.New()) diff --git a/main.go b/main.go index 82ab3c0..29d5ad2 100644 --- a/main.go +++ b/main.go @@ -153,6 +153,14 @@ func handleAuthRequest(res http.ResponseWriter, r *http.Request) { switch err { case plugins.ErrNoValidUserFound: + // No valid user found, check whether special anonymous "user" has access + // Username is set to 0x0 character to prevent accidential whitelist-match + if mainCfg.ACL.HasAccess(string(0x0), nil, r) { + mainCfg.AuditLog.Log(auditEventValidate, r, map[string]string{"result": "anonymous access granted"}) // #nosec G104 - This is only logging + res.WriteHeader(http.StatusOK) + return + } + mainCfg.AuditLog.Log(auditEventValidate, r, map[string]string{"result": "no valid user found"}) // #nosec G104 - This is only logging http.Error(res, "No valid user found", http.StatusUnauthorized)