Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use canonical name to derive SPN #274

Merged
merged 18 commits into from
Mar 10, 2019
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ language: go
go:
- 1.10.x
- 1.11.x
- 1.12.x
- master

go_import_path: gopkg.in/jcmturner/gokrb5.v7
Expand All @@ -16,7 +17,7 @@ before_install:
- sudo apt-get install -yq krb5-user
- sudo chmod 666 /etc/krb5.conf
- go get -u golang.org/x/lint/golint
- docker run -d -h ns.test.gokrb5 -v /etc/localtime:/etc/localtime:ro -e "TEST_KDC_ADDR=127.0.0.1" -p 53:53 -p 53:53/udp --name dns jcmturner/gokrb5:dns
- docker run -d -h ns.test.gokrb5 -v /etc/localtime:/etc/localtime:ro -e "TEST_KDC_ADDR=127.0.0.1" -e "TEST_HTTP_ADDR=127.0.0.1" -p 53:53 -p 53:53/udp --name dns jcmturner/gokrb5:dns
- docker run -d -h kdc.test.gokrb5 -v /etc/localtime:/etc/localtime:ro -p 88:88 -p 88:88/udp -p 464:464 -p 464:464/udp --name krb5kdc jcmturner/gokrb5:kdc-centos-default
- docker run -d -h kdc.test.gokrb5 -v /etc/localtime:/etc/localtime:ro -p 78:88 -p 78:88/udp --name krb5kdc-old jcmturner/gokrb5:kdc-older
- docker run -d -h kdc.test.gokrb5 -v /etc/localtime:/etc/localtime:ro -p 98:88 -p 98:88/udp --name krb5kdc-latest jcmturner/gokrb5:kdc-latest
Expand All @@ -29,7 +30,7 @@ before_script:
- sudo sed -i 's/nameserver .*/nameserver 127.0.0.1/g' /etc/resolv.conf

env:
- INTEGRATION=1 TESTPRIVILEGED=1 TEST_KDC_ADDR=127.0.0.1 TEST_HTTP_URL="http://host.test.gokrb5" DNSUTILS_OVERRIDE_NS="127.0.0.1:53" DEBIAN_FRONTEND=noninteractive
- INTEGRATION=1 TESTPRIVILEGED=1 TEST_KDC_ADDR=127.0.0.1 TEST_HTTP_URL="http://cname.test.gokrb5" TEST_HTTP_ADDR="127.0.0.1" DNSUTILS_OVERRIDE_NS="127.0.0.1:53" DEBIAN_FRONTEND=noninteractive

script:
- test -z $(gofmt -s -d -l -e $GO_FILES | tee /dev/fd/2 | xargs | sed 's/\s//g') # Fail if a .go file hasn't been formatted with gofmt
Expand All @@ -41,7 +42,6 @@ script:

addons:
hosts:
- host.test.gokrb5
- kdc.test.gokrb5
- kdc.resdom.gokrb5

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[![GoDoc](https://godoc.org/gopkg.in/jcmturner/gokrb5.v7?status.svg)](https://godoc.org/gopkg.in/jcmturner/gokrb5.v7) [![Go Report Card](https://goreportcard.com/badge/gopkg.in/jcmturner/gokrb5.v7)](https://goreportcard.com/report/gopkg.in/jcmturner/gokrb5.v7) [![Build Status](https://travis-ci.org/jcmturner/gokrb5.svg?branch=master)](https://travis-ci.org/jcmturner/gokrb5)

#### Go Version Support
![Go version](https://img.shields.io/badge/Go-1.12-brightgreen.svg)
![Go version](https://img.shields.io/badge/Go-1.11-brightgreen.svg)
![Go version](https://img.shields.io/badge/Go-1.10-brightgreen.svg)

Expand Down
11 changes: 10 additions & 1 deletion spnego/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
"net"
"net/http"
"net/http/cookiejar"
"net/url"
Expand Down Expand Up @@ -138,8 +139,16 @@ func respUnauthorizedNegotiate(resp *http.Response) bool {
// To auto generate the SPN from the request object pass a null string "".
func SetSPNEGOHeader(cl *client.Client, r *http.Request, spn string) error {
if spn == "" {
spn = "HTTP/" + strings.SplitN(r.Host, ":", 2)[0]
h := strings.TrimSuffix(strings.SplitN(r.URL.Host, ":", 2)[0], ".")
name, err := net.LookupCNAME(h)
if err == nil {
// Underlyng canonical name should be used for SPN
h = strings.TrimSuffix(name, ".")
}
spn = "HTTP/" + h
r.Host = h
}
cl.Log("using SPN %s", spn)
s := SPNEGOClient(cl, spn)
err := s.AcquireCred()
if err != nil {
Expand Down
113 changes: 52 additions & 61 deletions spnego/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ import (
"gopkg.in/jcmturner/gokrb5.v7/config"
"gopkg.in/jcmturner/gokrb5.v7/keytab"
"gopkg.in/jcmturner/gokrb5.v7/service"
"gopkg.in/jcmturner/gokrb5.v7/test"
"gopkg.in/jcmturner/gokrb5.v7/test/testdata"
)

func TestClient_SetSPNEGOHeader(t *testing.T) {
if os.Getenv("INTEGRATION") != "1" {
t.Skip("Skipping integration test")
}
test.Integration(t)
b, _ := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
kt := keytab.New()
kt.Unmarshal(b)
Expand All @@ -37,49 +36,46 @@ func TestClient_SetSPNEGOHeader(t *testing.T) {
addr = testdata.TEST_KDC_ADDR
}
c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
cl := client.NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt, c)
l := log.New(os.Stderr, "SPNEGO Client:", log.LstdFlags)
cl := client.NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt, c, client.Logger(l))

err := cl.Login()
if err != nil {
t.Fatalf("error on AS_REQ: %v\n", err)
}
url := os.Getenv("TEST_HTTP_URL")
if url == "" {
url = testdata.TEST_HTTP_URL
urls := []string{
"http://cname.test.gokrb5",
"http://host.test.gokrb5",
}
paths := []string{
"/modkerb/index.html",
"/modgssapi/index.html",
}
for _, p := range paths {
r, _ := http.NewRequest("GET", url+p, nil)
httpCl := http.DefaultClient
httpCl.CheckRedirect = func(req *http.Request, via []*http.Request) error {
t.Logf("http client redirect: %+v", *req)
return nil
}
httpResp, err := httpCl.Do(r)
if err != nil {
t.Fatalf("%s request error: %v", url+p, err)
}
assert.Equal(t, http.StatusUnauthorized, httpResp.StatusCode, "Status code in response to client with no SPNEGO not as expected")
err = SetSPNEGOHeader(cl, r, "HTTP/host.test.gokrb5")
if err != nil {
t.Fatalf("error setting client SPNEGO header: %v", err)
}
//t.Logf("Reqeust: %+v\n\n", *r)
httpResp, err = http.DefaultClient.Do(r)
if err != nil {
t.Fatalf("%s request error: %v\n", url+p, err)
//"/modgssapi/index.html",
}
for _, url := range urls {
for _, p := range paths {
r, _ := http.NewRequest("GET", url+p, nil)
httpResp, err := http.DefaultClient.Do(r)
if err != nil {
t.Fatalf("%s request error: %v", url+p, err)
}
assert.Equal(t, http.StatusUnauthorized, httpResp.StatusCode, "Status code in response to client with no SPNEGO not as expected")

err = SetSPNEGOHeader(cl, r, "")
if err != nil {
t.Fatalf("error setting client SPNEGO header: %v", err)
}

httpResp, err = http.DefaultClient.Do(r)
if err != nil {
t.Fatalf("%s request error: %v\n", url+p, err)
}
assert.Equal(t, http.StatusOK, httpResp.StatusCode, "Status code in response to client SPNEGO request not as expected")
}
assert.Equal(t, http.StatusOK, httpResp.StatusCode, "Status code in response to client SPNEGO request not as expected")
}
}

func TestSPNEGOHTTPClient(t *testing.T) {
if os.Getenv("INTEGRATION") != "1" {
t.Skip("Skipping integration test")
}
test.Integration(t)
b, _ := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
kt := keytab.New()
kt.Unmarshal(b)
Expand All @@ -89,35 +85,38 @@ func TestSPNEGOHTTPClient(t *testing.T) {
addr = testdata.TEST_KDC_ADDR
}
c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
cl := client.NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt, c)
l := log.New(os.Stderr, "SPNEGO Client:", log.LstdFlags)
cl := client.NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt, c, client.Logger(l))

err := cl.Login()
if err != nil {
t.Fatalf("error on AS_REQ: %v\n", err)
}
url := os.Getenv("TEST_HTTP_URL")
if url == "" {
url = testdata.TEST_HTTP_URL
urls := []string{
"http://cname.test.gokrb5",
"http://host.test.gokrb5",
}
// This path issues a redirect which the http client will automatically follow.
// It should cause a replay issue if the negInit token is sent in the first instance.
paths := []string{
"/modgssapi", // This issues a redirect which the http client will automatically follow. Could cause a replay issue
"/redirect",
}
for _, p := range paths {
r, _ := http.NewRequest("GET", url+p, nil)
httpCl := http.DefaultClient
httpCl.CheckRedirect = func(req *http.Request, via []*http.Request) error {
t.Logf("http client redirect: %+v", *req)
return nil
}
spnegoCl := NewClient(cl, httpCl, "HTTP/host.test.gokrb5")
httpResp, err := spnegoCl.Do(r)
if err != nil {
t.Fatalf("%s request error: %v", url+p, err)
for _, url := range urls {
for _, p := range paths {
r, _ := http.NewRequest("GET", url+p, nil)
httpCl := http.DefaultClient
httpCl.CheckRedirect = func(req *http.Request, via []*http.Request) error {
t.Logf("http client redirect: %+v", *req)
return nil
}
spnegoCl := NewClient(cl, httpCl, "")
httpResp, err := spnegoCl.Do(r)
if err != nil {
t.Fatalf("%s request error: %v", url+p, err)
}
assert.Equal(t, http.StatusOK, httpResp.StatusCode, "Status code in response to client SPNEGO request not as expected")
}
assert.Equal(t, http.StatusOK, httpResp.StatusCode, "Status code in response to client SPNEGO request not as expected")
}
}

Expand All @@ -134,9 +133,7 @@ func TestService_SPNEGOKRB_NoAuthHeader(t *testing.T) {
}

func TestService_SPNEGOKRB_ValidUser(t *testing.T) {
if os.Getenv("INTEGRATION") != "1" {
t.Skip("Skipping integration test")
}
test.Integration(t)

s := httpServer()
defer s.Close()
Expand All @@ -156,9 +153,7 @@ func TestService_SPNEGOKRB_ValidUser(t *testing.T) {
}

func TestService_SPNEGOKRB_Replay(t *testing.T) {
if os.Getenv("INTEGRATION") != "1" {
t.Skip("Skipping integration test")
}
test.Integration(t)

s := httpServer()
defer s.Close()
Expand Down Expand Up @@ -215,9 +210,7 @@ func TestService_SPNEGOKRB_Replay(t *testing.T) {
}

func TestService_SPNEGOKRB_ReplayCache_Concurrency(t *testing.T) {
if os.Getenv("INTEGRATION") != "1" {
t.Skip("Skipping integration test")
}
test.Integration(t)

s := httpServer()
defer s.Close()
Expand Down Expand Up @@ -255,9 +248,7 @@ func TestService_SPNEGOKRB_ReplayCache_Concurrency(t *testing.T) {
}

func TestService_SPNEGOKRB_Upload(t *testing.T) {
if os.Getenv("INTEGRATION") != "1" {
t.Skip("Skipping integration test")
}
test.Integration(t)

s := httpServer()
defer s.Close()
Expand Down
1 change: 1 addition & 0 deletions test/testenv/docker/dns/files/named.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/bin/bash

sed -i "s/<TEST_KDC_ADDR>/${TEST_KDC_ADDR}/g" /var/named/data/db.test.gokrb5
sed -i "s/<TEST_HTTP_ADDR>/${TEST_HTTP_ADDR}/g" /var/named/data/db.test.gokrb5

/usr/sbin/named -g -c /etc/named.conf -u bind -4
2 changes: 2 additions & 0 deletions test/testenv/docker/dns/files/zone-files/db.test.gokrb5
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ kdc1a IN A <TEST_KDC_ADDR>
kdc1b IN A <TEST_KDC_ADDR>
kdc2a IN A <TEST_KDC_ADDR>
kdc2b IN A <TEST_KDC_ADDR>
host IN A <TEST_HTTP_ADDR>
cname IN CNAME host