1package client 2 3import ( 4 "encoding/hex" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "runtime" 9 "sync" 10 "testing" 11 "time" 12 13 "github.com/jcmturner/gokrb5/v8/config" 14 "github.com/jcmturner/gokrb5/v8/iana/etypeID" 15 "github.com/jcmturner/gokrb5/v8/keytab" 16 "github.com/jcmturner/gokrb5/v8/test" 17 "github.com/jcmturner/gokrb5/v8/test/testdata" 18 "github.com/stretchr/testify/assert" 19) 20 21func TestMultiThreadedClientSession(t *testing.T) { 22 test.Integration(t) 23 24 b, _ := hex.DecodeString(testdata.TESTUSER1_KEYTAB) 25 kt := keytab.New() 26 kt.Unmarshal(b) 27 c, _ := config.NewFromString(testdata.TEST_KRB5CONF) 28 addr := os.Getenv("TEST_KDC_ADDR") 29 if addr == "" { 30 addr = testdata.TEST_KDC_ADDR 31 } 32 c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC} 33 cl := NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 34 err := cl.Login() 35 if err != nil { 36 t.Fatalf("failed to log in: %v", err) 37 } 38 39 s, ok := cl.sessions.get("TEST.GOKRB5") 40 if !ok { 41 t.Fatal("error initially getting session") 42 } 43 go func() { 44 for { 45 err := cl.renewTGT(s) 46 if err != nil { 47 t.Logf("error renewing TGT: %v", err) 48 } 49 time.Sleep(time.Millisecond * 100) 50 } 51 }() 52 53 var wg sync.WaitGroup 54 wg.Add(10) 55 for i := 0; i < 10; i++ { 56 go func() { 57 defer wg.Done() 58 tgt, _, err := cl.sessionTGT("TEST.GOKRB5") 59 if err != nil || tgt.Realm != "TEST.GOKRB5" { 60 t.Logf("error getting session: %v", err) 61 } 62 _, _, _, r, _ := cl.sessionTimes("TEST.GOKRB5") 63 fmt.Fprintf(ioutil.Discard, "%v", r) 64 }() 65 time.Sleep(time.Second) 66 } 67 wg.Wait() 68} 69 70func TestClient_AutoRenew_Goroutine(t *testing.T) { 71 test.Integration(t) 72 73 // Tests that the auto renew of client credentials is not spawning goroutines out of control. 74 addr := os.Getenv("TEST_KDC_ADDR") 75 if addr == "" { 76 addr = testdata.TEST_KDC_ADDR 77 } 78 b, _ := hex.DecodeString(testdata.TESTUSER2_KEYTAB) 79 kt := keytab.New() 80 kt.Unmarshal(b) 81 c, _ := config.NewFromString(testdata.TEST_KRB5CONF) 82 c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC_SHORTTICKETS} 83 c.LibDefaults.PreferredPreauthTypes = []int{int(etypeID.DES3_CBC_SHA1_KD)} // a preauth etype the KDC does not support. Test this does not cause renewal to fail. 84 cl := NewWithKeytab("testuser2", "TEST.GOKRB5", kt, c) 85 86 err := cl.Login() 87 if err != nil { 88 t.Errorf("error on logging in: %v\n", err) 89 } 90 n := runtime.NumGoroutine() 91 for i := 0; i < 24; i++ { 92 time.Sleep(time.Second * 5) 93 _, endTime, _, _, err := cl.sessionTimes("TEST.GOKRB5") 94 if err != nil { 95 t.Errorf("could not get client's session: %v", err) 96 } 97 if time.Now().UTC().After(endTime) { 98 t.Fatalf("session auto update failed") 99 } 100 spn := "HTTP/host.test.gokrb5" 101 tkt, key, err := cl.GetServiceTicket(spn) 102 if err != nil { 103 t.Fatalf("error getting service ticket: %v\n", err) 104 } 105 b, _ := hex.DecodeString(testdata.HTTP_KEYTAB) 106 skt := keytab.New() 107 skt.Unmarshal(b) 108 tkt.DecryptEncPart(skt, nil) 109 assert.Equal(t, spn, tkt.SName.PrincipalNameString()) 110 assert.Equal(t, int32(18), key.KeyType) 111 if runtime.NumGoroutine() > n { 112 t.Fatalf("number of goroutines is increasing: should not be more than %d, is %d", n, runtime.NumGoroutine()) 113 } 114 } 115} 116