github.com/jcmturner/gokrb5/v8@v8.4.4/client/session_test.go (about)

     1  package client
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"io"
     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  
    21  func TestMultiThreadedClientSession(t *testing.T) {
    22  	test.Integration(t)
    23  
    24  	b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5)
    25  	kt := keytab.New()
    26  	kt.Unmarshal(b)
    27  	c, _ := config.NewFromString(testdata.KRB5_CONF)
    28  	addr := os.Getenv("TEST_KDC_ADDR")
    29  	if addr == "" {
    30  		addr = testdata.KDC_IP_TEST_GOKRB5
    31  	}
    32  	c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5}
    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(io.Discard, "%v", r)
    64  		}()
    65  		time.Sleep(time.Second)
    66  	}
    67  	wg.Wait()
    68  }
    69  
    70  func 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.KDC_IP_TEST_GOKRB5
    77  	}
    78  	b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER2_TEST_GOKRB5)
    79  	kt := keytab.New()
    80  	kt.Unmarshal(b)
    81  	c, _ := config.NewFromString(testdata.KRB5_CONF)
    82  	c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5_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  
   117  func TestSessions_JSON(t *testing.T) {
   118  	s := &sessions{
   119  		Entries: make(map[string]*session),
   120  	}
   121  	for i := 0; i < 3; i++ {
   122  		realm := fmt.Sprintf("test%d", i)
   123  		e := &session{
   124  			realm:                realm,
   125  			authTime:             time.Unix(int64(0+i), 0).UTC(),
   126  			endTime:              time.Unix(int64(10+i), 0).UTC(),
   127  			renewTill:            time.Unix(int64(20+i), 0).UTC(),
   128  			sessionKeyExpiration: time.Unix(int64(30+i), 0).UTC(),
   129  		}
   130  		s.Entries[realm] = e
   131  	}
   132  	j, err := s.JSON()
   133  	if err != nil {
   134  		t.Errorf("error getting json: %v", err)
   135  	}
   136  	expected := `[
   137    {
   138      "Realm": "test0",
   139      "AuthTime": "1970-01-01T00:00:00Z",
   140      "EndTime": "1970-01-01T00:00:10Z",
   141      "RenewTill": "1970-01-01T00:00:20Z",
   142      "SessionKeyExpiration": "1970-01-01T00:00:30Z"
   143    },
   144    {
   145      "Realm": "test1",
   146      "AuthTime": "1970-01-01T00:00:01Z",
   147      "EndTime": "1970-01-01T00:00:11Z",
   148      "RenewTill": "1970-01-01T00:00:21Z",
   149      "SessionKeyExpiration": "1970-01-01T00:00:31Z"
   150    },
   151    {
   152      "Realm": "test2",
   153      "AuthTime": "1970-01-01T00:00:02Z",
   154      "EndTime": "1970-01-01T00:00:12Z",
   155      "RenewTill": "1970-01-01T00:00:22Z",
   156      "SessionKeyExpiration": "1970-01-01T00:00:32Z"
   157    }
   158  ]`
   159  	assert.Equal(t, expected, j, "json output not as expected")
   160  }