Browse Source

tests and docker testenv

Jonathan Turner 9 years ago
parent
commit
0174084baf

+ 80 - 0
client/client_integration_test.go

@@ -0,0 +1,80 @@
+// +build integration
+// To turn on this test use -tags=integration in go test command
+
+package client
+
+import (
+	"testing"
+	"encoding/hex"
+	"github.com/jcmturner/gokrb5/keytab"
+	"github.com/jcmturner/gokrb5/config"
+	"github.com/jcmturner/gokrb5/testdata"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestClient_SuccessfulLogin(t *testing.T) {
+	b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
+	cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
+	cl.WithConfig(c)
+
+	err = cl.Login()
+	if err != nil {
+		t.Fatalf("Error on login: %v\n", err)
+	}
+}
+
+func TestClient_FailedLogin(t *testing.T) {
+	b, err := hex.DecodeString(testdata.TESTUSER1_WRONGPASSWD)
+	kt, _ := keytab.Parse(b)
+	c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
+	cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
+	cl.WithConfig(c)
+
+	err = cl.Login()
+	if err == nil {
+		t.Fatal("Login with incorrect password did not error")
+	}
+}
+
+func TestClient_NetworkTimeout(t *testing.T) {
+	b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF_BAD_KDC_ADDRESS)
+	cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
+	cl.WithConfig(c)
+
+	err = cl.Login()
+	if err == nil {
+		t.Fatal("Login with incorrect KDC address did not error")
+	}
+}
+
+func TestClient_GetServiceTicket(t *testing.T) {
+	b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
+	cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
+	cl.WithConfig(c)
+
+	err = cl.Login()
+	if err != nil {
+		t.Fatalf("Error on login: %v\n", err)
+	}
+	spn := "HTTP/host.test.gokrb5"
+	tkt, key, err := cl.GetServiceTicket(spn)
+	if err != nil {
+		t.Fatalf("Error getting service ticket: %v\n", err)
+	}
+	assert.Equal(t, spn, tkt.SName.GetPrincipalNameString())
+	assert.Equal(t, 18, key.KeyType)
+
+	//Check cache use - should get the same values back again
+	tkt2, key2, err := cl.GetServiceTicket(spn)
+	if err != nil {
+		t.Fatalf("Error getting service ticket: %v\n", err)
+	}
+	assert.Equal(t, tkt.EncPart.Cipher, tkt2.EncPart.Cipher)
+	assert.Equal(t, key.KeyValue, key2.KeyValue)
+}

+ 4 - 3
example.go

@@ -57,9 +57,9 @@ func httpRequest(url string) {
 	if err != nil {
 		l.Printf("Request error: %v\n", err)
 	}
-	fmt.Fprintf(os.Stdout, "Response Body: %v\n", httpResp.StatusCode)
+	fmt.Fprintf(os.Stdout, "Response Code: %v\n", httpResp.StatusCode)
 	content, _ := ioutil.ReadAll(httpResp.Body)
-	fmt.Fprintf(os.Stdout, "Response Body: %s\n", content)
+	fmt.Fprintf(os.Stdout, "Response Body:\n%s\n", content)
 }
 
 func httpServer() *httptest.Server {
@@ -73,6 +73,7 @@ func httpServer() *httptest.Server {
 
 func testAppHandler(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
-	fmt.Fprintln(w, "TEST.GOKRB5 Handler")
+	ctx := r.Context()
+	fmt.Fprintf(w, "<html>\nTEST.GOKRB5 Handler\nAuthenticed user: %s\nUser's realm: %s\n</html>", ctx.Value("cname").(string), ctx.Value("crealm").(string))
 	return
 }

+ 7 - 4
iana/adtype/constants.go

@@ -2,8 +2,11 @@
 package adtype
 
 const (
-	AD_IF_RELEVANT       = 1
-	AD_KDCIssued         = 4
-	AD_AND_OR            = 5
-	AD_MANDATORY_FOR_KDC = 8
+	AD_IF_RELEVANT             = 1
+	AD_KDCIssued               = 4
+	AD_AND_OR                  = 5
+	AD_MANDATORY_FOR_KDC       = 8
+	AD_Authentication_Strength = 70
+	AD_FX_Fast_Armor           = 71
+	AD_FX_Fast_Used            = 72
 )

+ 11 - 5
iana/keyusage/constants.go

@@ -21,11 +21,17 @@ const (
 	//16-18.  Reserved for future use in Kerberos and related protocols.
 	AD_KDC_ISSUED_CHKSUM = 19
 	//20-21.  Reserved for future use in Kerberos and related protocols.
-	GSSAPI_ACCEPTOR_SEAL  = 22
-	GSSAPI_ACCEPTOR_SIGN  = 23
-	GSSAPI_INITIATOR_SEAL = 24
-	GSSAPI_INITIATOR_SIGN = 25
-	KEY_USAGE_AS_REQ      = 56
+	GSSAPI_ACCEPTOR_SEAL           = 22
+	GSSAPI_ACCEPTOR_SIGN           = 23
+	GSSAPI_INITIATOR_SEAL          = 24
+	GSSAPI_INITIATOR_SIGN          = 25
+	KEY_USAGE_FAST_REQ_CHKSUM      = 50
+	KEY_USAGE_FAST_ENC             = 51
+	KEY_USAGE_FAST_REP             = 52
+	KEY_USAGE_FAST_FINISHED        = 53
+	KEY_USAGE_ENC_CHALLENGE_CLIENT = 54
+	KEY_USAGE_ENC_CHALLENGE_KDC    = 55
+	KEY_USAGE_AS_REQ               = 56
 	//26-511.  Reserved for future use in Kerberos and related protocols.
 	//512-1023.  Reserved for uses internal to a Kerberos implementation.
 	//1024.  Encryption for application use in protocols that do not specify key usage values

+ 1 - 1
messages/KDCRep.go

@@ -229,7 +229,7 @@ func (k *ASRep) IsValid(cfg *config.Config, asReq ASReq) (bool, error) {
 		//			return false, fmt.Errorf("KDC FAST negotiation response error, %v", err)
 		//		}
 		//		ab, _ := asReq.Marshal()
-		//		if !crypto.VerifyChecksum(k.DecryptedEncPart.Key.KeyValue, pafast.Chksum, ab, keyusage.KEY_USAGE_AS_REQ, etype) {
+		//		if !engine.VerifyChecksum(k.DecryptedEncPart.Key.KeyValue, pafast.Chksum, ab, keyusage.KEY_USAGE_AS_REQ, etype) {
 		//			return false, errors.New("KDC FAST negotiation response checksum invalid")
 		//		}
 		//	}

+ 22 - 0
testdata/test_vectors.go

@@ -99,6 +99,7 @@ var TestVectors = map[string]string{
 
 const (
 	TESTUSER1_KEYTAB = "05020000003b0001000b544553542e474f4b52423500097465737475736572310000000158ee757c0100110010698c4df8e9f60e7eea5a21bf4526ad25000000010000004b0001000b544553542e474f4b52423500097465737475736572310000000158ee757c0100120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de900000001"
+	TESTUSER1_WRONGPASSWD = "0502000000370001000b544553542e474f4b52423500097465737475736572310000000158ef4bc5010011001039a9a382153105f8708e80f93382654e000000470001000b544553542e474f4b52423500097465737475736572310000000158ef4bc60100120020fc5bb940d6075214e0c6fc0456ce68c33306094198a927b4187d7cf3f4aea50d"
 	HTTP_KEYTAB      = "0502000000480002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b7262350000000158ee7636010011001057a7754c70c4d85c155c718c2f1292b000000001000000580002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b7262350000000158ee763601001200209cad00bbc72d703258e911dc18e6d5487cf737bf67fd111f0c2463ad6033bf5100000001"
 	TEST_AS_REQ      = "6a81a63081a3a103020105a20302010aa30e300c300aa10402020095a2020400a48186308183a00703050040000010a1163014a003020101a10d300b1b09746573747573657231a20d1b0b544553542e474f4b524235a320301ea003020102a11730151b066b72627467741b0b544553542e474f4b524235a511180f32303137303232303134323530315aa70602040f6755a6a814301202011202011102011002011702011902011a"
 	TEST_AS_REP      = "6b8202f3308202efa003020105a10302010ba22e302c302aa103020113a2230421301f301da003020112a1161b14544553542e474f4b524235746573747573657231a30d1b0b544553542e474f4b524235a4163014a003020101a10d300b1b09746573747573657231a582015a6182015630820152a003020105a10d1b0b544553542e474f4b524235a220301ea003020102a11730151b066b72627467741b0b544553542e474f4b524235a382011830820114a003020112a103020101a28201060482010264d3fa49d89b627ed471298846ff92cd8632f657c58fe25322a61fffa32bb7966dc4c44c86a81353def2a11c36c537191406a609147f424a63266c00d02bcc56a27b0969d86ff4352634be9e2a4ac0ad5a36b0b0a3d689f128c0afa97401796e88037a35ad19efaf31d1ed4f3213769c03a58bc90ffac2051db152c0ed0809ad05ffb03aa3afaf731ed85f7a73020cb72355e0de27842dcf7eae3de9f7c14aa237edb25153b217ef3693373bc3cacbebe406910ff9ae9d00b7b08f726cb29a213cb9ad51ba80a8c24fa4b6692a445686889702cfa6ea749bac03e27e982407aca623fbd48586bcf566cfe87e1d9f17a74b1315669c16480f93e9d8782e71a8f11000a682012c30820128a003020112a282011f0482011b99b86153c0393c0e4130628f3e1e0f0a1f034e7e61a111b7fad15884e231c8fd8727e0bc945c9b35be20c57d057c8b09b0de74c53fb38cc15c9a2d483023fc369f5bde4da7324b4732b5a3d9504d92f67026aaa01df4f0138245d2ccb1c5a4014804cf295c7e7e56a867e6cf0c534f667f32da7aa5e700af1461764f1c276a8ff0fbee0e99322fe2059d2321853be09d0956c3afcfd07e3e702646a4678926a77bea20d9aaf3086b6d384821c81900af9013a3519f0e50eab6e1491d72e4ee17c2a44441b2ebc8a796cc3d876e328347dce65f61104e14d4c31532885776c9c8a70186b8b39f928972945c98bd60381ead5448e7ebe93fea308054287ac34b0583b4b9b5e43c5f8518d693ba9eb48a219c27344466b3c693a70462"
@@ -124,4 +125,25 @@ const (
  .test.gokrb5 = TEST.GOKRB5
  test.gokrb5 = TEST.GOKRB5
  `
+	TEST_KRB5CONF_BAD_KDC_ADDRESS = `[libdefaults]
+  default_realm = TEST.GOKRB5
+  dns_lookup_realm = false
+  dns_lookup_kdc = false
+  ticket_lifetime = 24h
+  forwardable = yes
+  default_tkt_enctypes = aes256-cts-hmac-sha1-96
+  default_tgs_enctypes = aes256-cts-hmac-sha1-96
+
+[realms]
+ TEST.GOKRB5 = {
+  kdc = 10.80.88.153:88
+  admin_server = 10.80.88.153:749
+  default_domain = test.gokrb5
+ }
+
+[domain_realm]
+ .test.gokrb5 = TEST.GOKRB5
+ test.gokrb5 = TEST.GOKRB5
+ `
+
 )

+ 22 - 0
testenv/docker/krb5kdc/Dockerfile

@@ -0,0 +1,22 @@
+FROM centos:latest
+MAINTAINER Jonathan Turner <jt@jtnet.co.uk>
+
+EXPOSE 88
+
+RUN yum install -y \
+  krb5-server \
+  tcpdump krb5-workstation vim \
+ && yum clean all
+
+ADD krb5.conf /etc/krb5.conf
+ADD kdc.conf /var/kerberos/krb5kdc/kdc.conf
+ADD kadm5.acl /var/kerberos/krb5kdc/kadm5.acl
+ADD krb5kdc-init.sh /opt/krb5/bin/krb5kdc-init.sh
+RUN mkdir -p /opt/krb5/log && \
+  mkdir -p /var/log/kerberos && \
+  chmod 700 /opt/krb5/bin/krb5kdc-init.sh && /opt/krb5/bin/krb5kdc-init.sh && \
+  ln -sf /dev/stdout /var/log/krb5kdc.log
+
+ENTRYPOINT ["/usr/sbin/krb5kdc", "-n"]
+
+RUN yum update -y && yum clean all

+ 11 - 0
testenv/docker/krb5kdc/README.md

@@ -0,0 +1,11 @@
+# KDC Intergation Test Instance for TEST.GOKRB5
+
+DO NOT USE THIS CONTAINER FOR ANY PRODUCTION USE!!!
+
+To run:
+
+docker run -v /etc/localtime:/etc/localtime:ro -p 88:88 -p 88:88/udp --rm --name gokrb5-TEST-kdc jcmturner/jtnet/gokrb5-test-kdc-v1.0
+
+To build:
+docker build -t jcmturner/jtnet:gokrb5-test-kdc-v1.0 --force-rm=true --rm=true .
+docker push jcmturner/jtnet:gokrb5-test-kdc-v1.0

+ 4 - 0
testenv/docker/krb5kdc/kadm5.acl

@@ -0,0 +1,4 @@
+testuser1@TEST.GOKRB5	*
+*/admin@TEST.GOKRB5	*
+*/*@TEST.GOKRB5		i
+*@TEST.GOKRB5		i

+ 15 - 0
testenv/docker/krb5kdc/kdc.conf

@@ -0,0 +1,15 @@
+[kdcdefaults]
+ kdc_ports = 88
+ kdc_tcp_ports = 88
+
+[realms]
+ TEST.GOKRB5 = {
+  master_key_type = aes256-cts
+  max_life = 12h 0m 0s
+  max_renewable_life = 7d 0h 0m 0s
+  acl_file = /var/kerberos/krb5kdc/kadm5.acl
+  dict_file = /usr/share/dict/words
+  admin_keytab = /opt/krb5/data/kadm5.keytab
+  supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
+ }
+

+ 32 - 0
testenv/docker/krb5kdc/krb5.conf

@@ -0,0 +1,32 @@
+[logging]
+ default = FILE:/var/log/krb5libs.log
+ kdc = FILE:/var/log/krb5kdc.log
+ admin_server = FILE:/var/log/kadmind.log
+
+
+[libdefaults]
+  default_realm = TEST.GOKRB5
+  dns_lookup_realm = false
+  dns_lookup_kdc = false
+  ticket_lifetime = 24h
+  forwardable = yes
+
+[realms]
+ TEST.GOKRB5 = {
+  kdc = 127.0.0.1:88
+  admin_server = 127.0.0.1:749
+  default_domain = test.gokrb5
+ }
+
+[domain_realm]
+ .test.gokrb5 = TEST.GOKRB5
+ test.gokrb5 = TEST.GOKRB5
+
+[appdefaults]
+ pam = {
+   debug = false
+   ticket_lifetime = 36000
+   renew_lifetime = 36000
+   forwardable = true
+   krb4_convert = false
+ }

+ 61 - 0
testenv/docker/krb5kdc/krb5kdc-init.sh

@@ -0,0 +1,61 @@
+#!/bin/bash
+
+REALM=TEST.GOKRB5
+DOMAIN=test.gokrb5
+SERVER_HOST=kdc.test.gokrb5
+ADMIN_USERNAME=adminuser
+HOST_PRINCIPALS="kdc.test.gokrb5 host.test.gokrb5"
+SPNs="HTTP/host.test.gokrb5"
+INITIAL_USERS="testuser1 testuser2 testuser3"
+
+create_entropy() {
+   while true
+   do
+     sleep $(( ( RANDOM % 10 )  + 1 ))
+     echo "Generating Entropy... $RANDOM"
+   done
+}
+
+create_entropy &
+ENTROPY_PID=$!
+
+
+  echo "Kerberos initialisation required. Creating database for ${REALM} ..."
+  echo "This can take a long time if there is little entropy. A process has been started to create some."
+  MASTER_PASSWORD=$(echo $RANDOM$RANDOM$RANDOM | md5sum | awk '{print $1}')
+  /usr/sbin/kdb5_util create -r ${REALM} -s -P ${MASTER_PASSWORD}
+  echo "Kerberos database created."
+  /usr/sbin/kadmin.local -q "add_principal -randkey ${ADMIN_USERNAME}/admin"
+  echo "Kerberos admin user created: ${ADMIN_USERNAME} To update password: sudo /usr/sbin/kadmin.local -q \"change_password ${ADMIN_USERNAME}/admin\""
+
+  KEYTAB_DIR="/opt/krb5/data/keytabs"
+  mkdir -p $KEYTAB_DIR
+
+  if [ ! -z "${HOST_PRINCIPALS}" ]; then
+    for host in ${HOST_PRINCIPALS}
+    do
+      /usr/sbin/kadmin.local -q "add_principal -pw hostpasswordvalue -kvno 1 host/$host"
+      echo "Created host principal host/$host"
+    done
+  fi
+
+  if [ ! -z "${SPNs}" ]; then
+    for service in ${SPNs}
+    do
+      /usr/sbin/kadmin.local -q "add_principal -pw spnpasswordvalue -kvno 1 ${service}"
+      echo "Created principal for service $service"
+    done
+  fi
+
+  if [ ! -z "$INITIAL_USERS" ]; then
+    for user in $INITIAL_USERS
+    do
+      /usr/sbin/kadmin.local -q "add_principal -pw passwordvalue -kvno 1 $user"
+      echo "User $user added to kerberos database. To update password: sudo /usr/sbin/kadmin.local -q \"change_password $user\""
+    done
+  fi
+
+  echo "Kerberos initialisation complete"
+
+#Start the kdc 
+kill -9 $ENTROPY_PID

+ 25 - 0
testenv/docker/krbhttp/Dockerfile

@@ -0,0 +1,25 @@
+FROM centos:latest
+MAINTAINER Jonathan Turner <jt@jtnet.co.uk>
+
+EXPOSE 80 443
+ENV LANG C
+ENTRYPOINT ["/usr/sbin/httpd", "-DFOREGROUND"]
+
+RUN yum install -y \
+  httpd \
+  mod_auth_kerb \
+  mod_ssl \
+  tcpdump krb5-workstation vim \
+ && yum clean all
+
+ADD krb5.conf /etc/krb5.conf
+ADD http.testtab /etc/httpd/
+ADD httpd-krb5.conf /etc/httpd/conf.d/
+ADD index.html /var/www/html/index.html
+RUN ln -sf /dev/stdout /var/log/httpd/access_log && \
+ ln -sf /dev/stdout /var/log/httpd/ssl_access_log && \
+ ln -sf /dev/stdout /var/log/httpd/ssl_request_log && \
+ ln -sf /dev/stderr /var/log/httpd/error_log && \
+ ln -sf /dev/stderr /var/log/httpd/ssl_error_log
+
+RUN yum update -y && yum clean all

+ 11 - 0
testenv/docker/krbhttp/README.md

@@ -0,0 +1,11 @@
+# Intergation Test Instance for TEST.GOKRB5
+
+DO NOT USE THIS CONTAINER FOR ANY PRODUCTION USE!!!
+
+To run:
+
+docker run -v /etc/localtime:/etc/localtime:ro -p 80:80 -p 443:443 --rm --name gokrb5-TEST-httpd jcmturner/jtnet:gokrb5-test-httpd-v1.0
+
+To build:
+docker build -t jcmturner/jtnet:gokrb5-test-httpd-v1.0 --force-rm=true --rm=true .
+docker push jcmturner/jtnet:gokrb5-test-httpd-v1.0

BIN
testenv/docker/krbhttp/http.testtab


+ 14 - 0
testenv/docker/krbhttp/httpd-krb5.conf

@@ -0,0 +1,14 @@
+LimitRequestFieldSize 65536
+ProxyIOBufferSize 65536
+<LocationMatch />
+        AuthType Kerberos
+        AuthName "TEST"
+        KrbServiceName HTTP
+        KrbMethodNegotiate On
+        KrbMethodK5Passwd On
+        KrbLocalUserMapping On
+        KrbAuthRealms TEST.GOKRB5
+        Krb5KeyTab /vagrant/http.testtab
+        #KrbSaveCredentials On
+        require valid-user
+</LocationMatch>

+ 1 - 0
testenv/docker/krbhttp/index.html

@@ -0,0 +1 @@
+<html>TEST.GOKRB5</html>

+ 26 - 0
testenv/docker/krbhttp/krb5.conf

@@ -0,0 +1,26 @@
+[libdefaults]
+  default_realm = TEST.GOKRB5
+  dns_lookup_realm = false
+  dns_lookup_kdc = false
+  ticket_lifetime = 24h
+  forwardable = yes
+
+[realms]
+ TEST.GOKRB5 = {
+  kdc = gokrb5-TEST-kdc:88
+  admin_server = gokrb5-TEST-kdc:749
+  default_domain = test.gokrb5
+ }
+
+[domain_realm]
+ .test.gokrb5 = TEST.GOKRB5
+ test.gokrb5 = TEST.GOKRB5
+
+[appdefaults]
+ pam = {
+   debug = false
+   ticket_lifetime = 36000
+   renew_lifetime = 36000
+   forwardable = true
+   krb4_convert = false
+ }