Skip to content

Commit

Permalink
Handle empty net.LookupCNAME response
Browse files Browse the repository at this point in the history
* See golang/go#44741
* When "pure go" resolver is used and host is present in /etc/hosts
  net.LookupCNAME() can return an empty string whitout any error
  • Loading branch information
riton committed Mar 3, 2021
1 parent 663478b commit b713656
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 4 deletions.
12 changes: 8 additions & 4 deletions v8/spnego/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ type teeReadCloser struct {
io.Closer
}

var (
testHookNetLookupCNAME = net.LookupCNAME
)

// NewClient returns a SPNEGO enabled HTTP client.
// Be careful when passing in the *http.Client if it is beginning reused in multiple calls to this function.
// Ensure reuse of the provided *http.Client is for the same user as a session cookie may have been added to
Expand Down Expand Up @@ -174,17 +178,17 @@ func setRequestSPN(r *http.Request) (types.PrincipalName, error) {
if err != nil {
return types.PrincipalName{}, err
}
name, err := net.LookupCNAME(h)
if err == nil {
name, err := testHookNetLookupCNAME(h)
if name != "" && err == nil {
// Underlyng canonical name should be used for SPN
h = name
}
h = strings.TrimSuffix(h, ".")
r.Host = fmt.Sprintf("%s:%s", h, p)
return types.NewPrincipalName(nametype.KRB_NT_PRINCIPAL, "HTTP/"+h), nil
}
name, err := net.LookupCNAME(h)
if err == nil {
name, err := testHookNetLookupCNAME(h)
if name != "" && err == nil {
// Underlyng canonical name should be used for SPN
h = name
}
Expand Down
28 changes: 28 additions & 0 deletions v8/spnego/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"net/http"
"net/http/cookiejar"
"net/http/httptest"
"net/url"
"os"
"sync"
"testing"
Expand Down Expand Up @@ -330,6 +331,33 @@ func TestService_SPNEGOKRB_Upload(t *testing.T) {
}
}

func TestRequest_setRequestSPN_EmptyCNAMEResponse(t *testing.T) {
url, _ := url.Parse("https://cc.in2p3.fr/ipa/session/login_kerberos")
r, _ := http.NewRequest("POST", url.String(), nil)

// simulate the "pure golang" resolver behavior
// if name is present in /etc/hosts
// See https://github.com/golang/go/issues/44741
testHookNetLookupCNAME = func(string) (string, error) {
return "", nil
}

pName, err := setRequestSPN(r)
if err != nil {
t.Fatalf("setRequestSPN failed: %s", err)
}

// If host is present in /etc/hosts and "pure golang" resolver is used
// we want to avoid the service principal to result in "HTTP/"
if pName.NameString[1] == "" {
t.Error("empty host in HTTP service principal name")
}

if pName.NameString[1] != url.Host {
t.Errorf("HTTP principal host is %s while %s was expected", pName.NameString[1], url.Host)
}
}

func httpGet(r *http.Request, wg *sync.WaitGroup) {
defer wg.Done()
http.DefaultClient.Do(r)
Expand Down

0 comments on commit b713656

Please sign in to comment.