From fb08c99bc0e8a51bed500468e272748494b65925 Mon Sep 17 00:00:00 2001 From: Basha Mougamadou Date: Fri, 1 Sep 2023 17:48:23 +0200 Subject: [PATCH] Migrate library haproxy-spoe-go Since our library https://github.com/criteo/haproxy-spoe-go has not been updated since a while and that some part of the specification are not well respected (here field engine-id and capability pipelining should be optional), migrate to a better maintained library. Using this library, we could now enable the spop-check in HAProxy for this component. --- go.mod | 3 +- go.sum | 17 +-- internal/agent/agent.go | 56 ++++----- internal/auth/authenticator.go | 7 +- internal/auth/authenticator_ldap.go | 48 ++++---- internal/auth/authenticator_oidc.go | 177 ++++++++++++---------------- internal/auth/messages.go | 26 ++-- 7 files changed, 143 insertions(+), 191 deletions(-) diff --git a/go.mod b/go.mod index 9c757c0..48f0503 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.20 require ( github.com/coreos/go-oidc/v3 v3.5.0 - github.com/criteo/haproxy-spoe-go v1.0.6 github.com/go-ldap/ldap/v3 v3.4.4 + github.com/negasus/haproxy-spoe-go v1.0.5 github.com/sirupsen/logrus v1.9.0 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.8.1 @@ -26,7 +26,6 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cast v1.5.0 // indirect diff --git a/go.sum b/go.sum index 05f69fb..6367f0c 100644 --- a/go.sum +++ b/go.sum @@ -59,9 +59,6 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/coreos/go-oidc/v3 v3.5.0 h1:VxKtbccHZxs8juq7RdJntSqtXFtde9YpNpGn0yqgEHw= github.com/coreos/go-oidc/v3 v3.5.0/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/criteo/haproxy-spoe-go v1.0.6 h1:3GDQ8hm/fIkn4wxxI/pN0OoBfKon4ROzvpU5fIriYII= -github.com/criteo/haproxy-spoe-go v1.0.6/go.mod h1:o04s69MOZ7SvPthMtUt/tfn1hcorQQAS/nwzKPBlXQU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -155,22 +152,20 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/negasus/haproxy-spoe-go v1.0.5 h1:iMUOg/WTdwh4qOD5VUWqXElIG6YefqdOZbTzbVXN8ZU= +github.com/negasus/haproxy-spoe-go v1.0.5/go.mod h1:ZrBizxtx2EeLN37Jkg9w9g32a1AFCJizA8vg46PaAp4= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -178,7 +173,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= @@ -338,7 +332,6 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -359,7 +352,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -538,16 +530,13 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/agent/agent.go b/internal/agent/agent.go index dc061cb..187d0f3 100644 --- a/internal/agent/agent.go +++ b/internal/agent/agent.go @@ -2,69 +2,69 @@ package agent import ( "log" + "net" + "os" "github.com/criteo/haproxy-spoe-auth/internal/auth" - spoe "github.com/criteo/haproxy-spoe-go" + "github.com/negasus/haproxy-spoe-go/action" + "github.com/negasus/haproxy-spoe-go/agent" + "github.com/negasus/haproxy-spoe-go/logger" + "github.com/negasus/haproxy-spoe-go/request" "github.com/sirupsen/logrus" ) // NotAuthenticatedMessage SPOE response stating the user is not authenticated -var NotAuthenticatedMessage = spoe.ActionSetVar{ - Name: "is_authenticated", - Scope: spoe.VarScopeSession, - Value: false, -} +var NotAuthenticatedMessage = action.NewSetVar(action.ScopeSession, "is_authenticated", false) // AuthenticatedMessage SPOE response stating the user is authenticated -var AuthenticatedMessage = spoe.ActionSetVar{ - Name: "is_authenticated", - Scope: spoe.VarScopeSession, - Value: true, -} +var AuthenticatedMessage = action.NewSetVar(action.ScopeSession, "is_authenticated", true) // StartAgent start the agent func StartAgent(interfaceAddr string, authenticators map[string]auth.Authenticator) { - agent := spoe.New(func(messages *spoe.MessageIterator) ([]spoe.Action, error) { - var actions []spoe.Action - + agent := agent.New(func(request *request.Request) { var authenticated bool = false var hasError bool = false - for messages.Next() { - msg := messages.Message - logrus.Debugf("new message with name %s received", msg.Name) + for authentifier_name, authentifier := range authenticators { + msg, err := request.Messages.GetByName(authentifier_name) + if err == nil { + logrus.Debugf("new message with name %s received", msg.Name) - authentifier, ok := authenticators[msg.Name] - if ok { - isAuthenticated, replyActions, err := authentifier.Authenticate(&msg) + isAuthenticated, replyActions, err := authentifier.Authenticate(msg) if err != nil { logrus.Errorf("unable to authenticate user: %v", err) hasError = true break } - actions = append(actions, replyActions...) + request.Actions = append(request.Actions, replyActions...) if isAuthenticated { authenticated = true } + break } } if hasError { - actions = append(actions, auth.BuildHasErrorMessage()) + request.Actions = append(request.Actions, auth.BuildHasErrorMessage()) } else { if authenticated { - actions = append(actions, AuthenticatedMessage) + request.Actions = append(request.Actions, AuthenticatedMessage) } else { - actions = append(actions, NotAuthenticatedMessage) + request.Actions = append(request.Actions, NotAuthenticatedMessage) } - } - return actions, nil - }) + }, logger.NewDefaultLog()) + + listener, err := net.Listen("tcp", interfaceAddr) + if err != nil { + log.Printf("error create listener, %v", err) + os.Exit(1) + } + defer listener.Close() logrus.Infof("agent starting and listening on %s with %d authenticators", interfaceAddr, len(authenticators)) - if err := agent.ListenAndServe(interfaceAddr); err != nil { + if err := agent.Serve(listener); err != nil { log.Fatal(err) } } diff --git a/internal/auth/authenticator.go b/internal/auth/authenticator.go index 0a2f487..43661a9 100644 --- a/internal/auth/authenticator.go +++ b/internal/auth/authenticator.go @@ -1,9 +1,12 @@ package auth -import spoe "github.com/criteo/haproxy-spoe-go" +import ( + action "github.com/negasus/haproxy-spoe-go/action" + message "github.com/negasus/haproxy-spoe-go/message" +) // Authenticator the authenticator interface that can be implemented for LDAP, OAuth2, OIDC or whatever else. type Authenticator interface { // Check whether the user is authenticated by this authenticator - Authenticate(msg *spoe.Message) (bool, []spoe.Action, error) + Authenticate(msg *message.Message) (bool, []action.Action, error) } diff --git a/internal/auth/authenticator_ldap.go b/internal/auth/authenticator_ldap.go index d9fb72c..c82a382 100644 --- a/internal/auth/authenticator_ldap.go +++ b/internal/auth/authenticator_ldap.go @@ -6,7 +6,9 @@ import ( "fmt" "strings" - spoe "github.com/criteo/haproxy-spoe-go" + action "github.com/negasus/haproxy-spoe-go/action" + message "github.com/negasus/haproxy-spoe-go/message" + "github.com/go-ldap/ldap/v3" "github.com/sirupsen/logrus" ) @@ -102,39 +104,35 @@ func parseBasicAuth(auth string) (username, password string, err error) { } // Authenticate handle an authentication request coming from HAProxy -func (la *LDAPAuthenticator) Authenticate(msg *spoe.Message) (bool, []spoe.Action, error) { - var authorization string +func (la *LDAPAuthenticator) Authenticate(msg *message.Message) (bool, []action.Action, error) { + authorization := "" group := "" isGroupProvided := false - for msg.Args.Next() { - arg := msg.Args.Arg - - if arg.Name == "authorization" { - var ok bool - authorization, ok = arg.Value.(string) - if !ok { - return false, nil, nil - } - } else if arg.Name == "authorized_group" { - var ok bool - group, ok = arg.Value.(string) - if !ok { - group = "" - } - isGroupProvided = true + authorizationValue, ok := msg.KV.Get("authorization") + if ok { + authorization, ok = authorizationValue.(string) + if !ok { + return false, nil, nil } } - - if isGroupProvided { - logrus.Debug(fmt.Sprintf("Group is <%s>", group)) - } - if authorization == "" { logrus.Debug("Authorization header is empty") return false, nil, nil } + authorizedGroupValue, ok := msg.KV.Get("authorized_group") + if ok { + group, ok = authorizedGroupValue.(string) + if !ok { + group = "" + } + isGroupProvided = true + } + if isGroupProvided { + logrus.Debug(fmt.Sprintf("Group is <%s>", group)) + } + username, password, err := parseBasicAuth(authorization) if err != nil { @@ -159,5 +157,5 @@ func (la *LDAPAuthenticator) Authenticate(msg *spoe.Message) (bool, []spoe.Actio } logrus.Debug("User is authenticated") - return true, []spoe.Action{AuthenticatedUserMessage(username)}, nil + return true, []action.Action{AuthenticatedUserMessage(username)}, nil } diff --git a/internal/auth/authenticator_oidc.go b/internal/auth/authenticator_oidc.go index b59f79e..0c7c839 100644 --- a/internal/auth/authenticator_oidc.go +++ b/internal/auth/authenticator_oidc.go @@ -14,7 +14,9 @@ import ( "github.com/vmihailenco/msgpack/v5" "github.com/coreos/go-oidc/v3/oidc" - spoe "github.com/criteo/haproxy-spoe-go" + action "github.com/negasus/haproxy-spoe-go/action" + message "github.com/negasus/haproxy-spoe-go/message" + "golang.org/x/oauth2" ) @@ -177,129 +179,103 @@ func (oa *OIDCAuthenticator) checkCookie(cookieValue string, domain string) erro return err } -func extractOAuth2Args(msg *spoe.Message, readClientInfoFromMessages bool) (OAuthArgs, error) { - var ssl *bool - var host, pathq *string +func extractOAuth2Args(msg *message.Message, readClientInfoFromMessages bool) (OAuthArgs, error) { var cookie string var clientid, clientsecret, redirecturl *string - for msg.Args.Next() { - arg := msg.Args.Arg - - if arg.Name == "arg_ssl" { - x, ok := arg.Value.(bool) - if !ok { - return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, - fmt.Errorf("SSL is not a bool: %v", arg.Value) - } - - ssl = new(bool) - *ssl = x - continue - } - - if arg.Name == "arg_host" { - x, ok := arg.Value.(string) - if !ok { - return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, - fmt.Errorf("host is not a string: %v", arg.Value) - } - - host = new(string) - *host = x - continue - } - - if arg.Name == "arg_pathq" { - x, ok := arg.Value.(string) - if !ok { - return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, - fmt.Errorf("pathq is not a string: %v", arg.Value) - } + // ssl + sslValue, ok := msg.KV.Get("arg_ssl") + if !ok { + return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, + ErrSSLArgNotFound + } + ssl, ok := sslValue.(bool) + if !ok { + return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, + fmt.Errorf("SSL is not a bool: %v", sslValue) + } - pathq = new(string) - *pathq = x - continue - } + // host + hostValue, ok := msg.KV.Get("arg_host") + if !ok { + return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, + ErrHostArgNotFound + } + host, ok := hostValue.(string) + if !ok { + return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, + fmt.Errorf("host is not a string: %v", hostValue) + } - if arg.Name == "arg_cookie" { - x, ok := arg.Value.(string) - if !ok { - continue - } + // pathq + pathqValue, ok := msg.KV.Get("arg_pathq") + if !ok { + return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, + ErrPathqArgNotFound + } + pathq, ok := pathqValue.(string) + if !ok { + return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, + fmt.Errorf("pathq is not a string: %v", pathqValue) + } - cookie = x - continue - } + // cookie + cookieValue, ok := msg.KV.Get("arg_cookie") + if ok { + cookie, _ = cookieValue.(string) + } - if arg.Name == "arg_client_id" { - if !readClientInfoFromMessages { - continue - } - x, ok := arg.Value.(string) + if readClientInfoFromMessages { + // client_id + clientidValue, ok := msg.KV.Get("arg_client_id") + if !ok { + logrus.Debugf("clientid is not defined : %v", clientidValue) + } else { + clientidStr, ok := clientidValue.(string) if !ok { - logrus.Debugf("clientid is not defined or not a string: %v", arg.Value) - continue + logrus.Debugf("clientid is not a string: %v", clientidValue) + } else { + clientid = new(string) + *clientid = clientidStr } - - clientid = new(string) - *clientid = x - continue } - if arg.Name == "arg_client_secret" { - if !readClientInfoFromMessages { - continue - } - x, ok := arg.Value.(string) + // client_secret + clientsecretValue, ok := msg.KV.Get("arg_client_secret") + if !ok { + logrus.Debugf("clientsecret is not defined : %v", clientsecretValue) + } else { + clientsecretStr, ok := clientsecretValue.(string) if !ok { - logrus.Debugf("clientsecret is not defined or not a string: %v", arg.Value) - continue + logrus.Debugf("clientsecret is not a string: %v", clientsecretValue) + } else { + clientsecret = new(string) + *clientsecret = clientsecretStr } - - clientsecret = new(string) - *clientsecret = x - continue } - if arg.Name == "arg_redirect_url" { - if !readClientInfoFromMessages { - continue - } - x, ok := arg.Value.(string) + // redirect_url + redirecturlValue, ok := msg.KV.Get("arg_redirect_url") + if !ok { + logrus.Debugf("redirecturl is not defined : %v", redirecturlValue) + } else { + redirecturlStr, ok := redirecturlValue.(string) if !ok { - logrus.Debugf("redirecturl is not defined or not a string: %v", arg.Value) - continue + logrus.Debugf("redirecturl is not a string: %v", redirecturlValue) + } else { + redirecturl = new(string) + *redirecturl = redirecturlStr } - - redirecturl = new(string) - *redirecturl = x - continue } } - if ssl == nil { - return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, - ErrSSLArgNotFound - } - - if host == nil { - return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, - ErrHostArgNotFound - } - - if pathq == nil { - return OAuthArgs{ssl: false, host: "", pathq: "", cookie: "", clientid: "", clientsecret: "", redirecturl: ""}, - ErrPathqArgNotFound - } - if clientid == nil || clientsecret == nil || redirecturl == nil { temp := "" clientid = &temp clientsecret = &temp redirecturl = &temp } - return OAuthArgs{ssl: *ssl, host: *host, pathq: *pathq, + return OAuthArgs{ssl: ssl, host: host, pathq: pathq, cookie: cookie, clientid: *clientid, clientsecret: *clientsecret, redirecturl: *redirecturl}, nil @@ -326,8 +302,7 @@ func extractDomainFromHost(host string) string { } // Authenticate treat an authentication request coming from HAProxy -func (oa *OIDCAuthenticator) Authenticate(msg *spoe.Message) (bool, []spoe.Action, error) { - // ssl, host, pathq, clientid, clientsecret, redirecturl, cookieValue, err := extractOAuth2Args(msg, oa.options.ReadClientInfoFromMessages) +func (oa *OIDCAuthenticator) Authenticate(msg *message.Message) (bool, []action.Action, error) { oauthArgs, err := extractOAuth2Args(msg, oa.options.ReadClientInfoFromMessages) if err != nil { return false, nil, fmt.Errorf("unable to extract origin URL: %v", err) @@ -378,7 +353,7 @@ func (oa *OIDCAuthenticator) Authenticate(msg *spoe.Message) (bool, []spoe.Actio return false, nil, fmt.Errorf("unable to build authorize url: %w", err) } - return false, []spoe.Action{BuildRedirectURLMessage(authorizationURL)}, nil + return false, []action.Action{BuildRedirectURLMessage(authorizationURL)}, nil } func (oa *OIDCAuthenticator) handleOAuth2Logout() http.HandlerFunc { diff --git a/internal/auth/messages.go b/internal/auth/messages.go index ddeb4ae..d5bcc0e 100644 --- a/internal/auth/messages.go +++ b/internal/auth/messages.go @@ -1,30 +1,18 @@ package auth -import spoe "github.com/criteo/haproxy-spoe-go" +import action "github.com/negasus/haproxy-spoe-go/action" // BuildRedirectURLMessage build a message containing the URL the user should be redirected too -func BuildRedirectURLMessage(url string) spoe.ActionSetVar { - return spoe.ActionSetVar{ - Name: "redirect_url", - Scope: spoe.VarScopeSession, - Value: url, - } +func BuildRedirectURLMessage(url string) action.Action { + return action.NewSetVar(action.ScopeSession, "redirect_url", url) } // BuildHasErrorMessage build a message stating an error was thrown in SPOE agent -func BuildHasErrorMessage() spoe.ActionSetVar { - return spoe.ActionSetVar{ - Name: "has_error", - Scope: spoe.VarScopeSession, - Value: true, - } +func BuildHasErrorMessage() action.Action { + return action.NewSetVar(action.ScopeSession, "has_error", true) } // AuthenticatedUserMessage build a message containing the username of the authenticated user -func AuthenticatedUserMessage(username string) spoe.ActionSetVar { - return spoe.ActionSetVar{ - Name: "authenticated_user", - Scope: spoe.VarScopeSession, - Value: username, - } +func AuthenticatedUserMessage(username string) action.Action { + return action.NewSetVar(action.ScopeSession, "authenticated_user", username) }