github.com/jcmturner/gokrb5/v8@v8.4.4/client/client_integration_test.go (about) 1 package client_test 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "errors" 7 "io" 8 "net/http" 9 "os" 10 "os/exec" 11 "os/user" 12 "runtime" 13 "testing" 14 "time" 15 16 "fmt" 17 "github.com/jcmturner/gokrb5/v8/client" 18 "github.com/jcmturner/gokrb5/v8/config" 19 "github.com/jcmturner/gokrb5/v8/credentials" 20 "github.com/jcmturner/gokrb5/v8/iana/etypeID" 21 "github.com/jcmturner/gokrb5/v8/keytab" 22 "github.com/jcmturner/gokrb5/v8/spnego" 23 "github.com/jcmturner/gokrb5/v8/test" 24 "github.com/jcmturner/gokrb5/v8/test/testdata" 25 "github.com/stretchr/testify/assert" 26 "strings" 27 "sync" 28 ) 29 30 func TestClient_SuccessfulLogin_Keytab(t *testing.T) { 31 test.Integration(t) 32 33 addr := os.Getenv("TEST_KDC_ADDR") 34 if addr == "" { 35 addr = testdata.KDC_IP_TEST_GOKRB5 36 } 37 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 38 kt := keytab.New() 39 kt.Unmarshal(b) 40 c, _ := config.NewFromString(testdata.KRB5_CONF) 41 var tests = []string{ 42 testdata.KDC_PORT_TEST_GOKRB5, 43 testdata.KDC_PORT_TEST_GOKRB5_OLD, 44 testdata.KDC_PORT_TEST_GOKRB5_LASTEST, 45 } 46 for _, tst := range tests { 47 c.Realms[0].KDC = []string{addr + ":" + tst} 48 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 49 50 err := cl.Login() 51 if err != nil { 52 t.Errorf("error on logging in with KDC %s: %v\n", tst, err) 53 } 54 } 55 } 56 57 func TestClient_SuccessfulLogin_Password(t *testing.T) { 58 test.Integration(t) 59 60 addr := os.Getenv("TEST_KDC_ADDR") 61 if addr == "" { 62 addr = testdata.KDC_IP_TEST_GOKRB5 63 } 64 c, _ := config.NewFromString(testdata.KRB5_CONF) 65 var tests = []string{ 66 testdata.KDC_PORT_TEST_GOKRB5, 67 testdata.KDC_PORT_TEST_GOKRB5_OLD, 68 testdata.KDC_PORT_TEST_GOKRB5_LASTEST, 69 } 70 for _, tst := range tests { 71 c.Realms[0].KDC = []string{addr + ":" + tst} 72 cl := client.NewWithPassword("testuser1", "TEST.GOKRB5", "passwordvalue", c) 73 74 err := cl.Login() 75 if err != nil { 76 t.Errorf("error on logging in with KDC %s: %v\n", tst, err) 77 } 78 } 79 } 80 81 func TestClient_SuccessfulLogin_TCPOnly(t *testing.T) { 82 test.Integration(t) 83 84 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 85 kt := keytab.New() 86 kt.Unmarshal(b) 87 c, _ := config.NewFromString(testdata.KRB5_CONF) 88 addr := os.Getenv("TEST_KDC_ADDR") 89 if addr == "" { 90 addr = testdata.KDC_IP_TEST_GOKRB5 91 } 92 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 93 c.LibDefaults.UDPPreferenceLimit = 1 94 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 95 96 err := cl.Login() 97 if err != nil { 98 t.Fatalf("error on login: %v\n", err) 99 } 100 } 101 102 func TestClient_ASExchange_TGSExchange_EncTypes_Keytab(t *testing.T) { 103 test.Integration(t) 104 105 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 106 kt := keytab.New() 107 kt.Unmarshal(b) 108 c, _ := config.NewFromString(testdata.KRB5_CONF) 109 addr := os.Getenv("TEST_KDC_ADDR") 110 if addr == "" { 111 addr = testdata.KDC_IP_TEST_GOKRB5 112 } 113 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5_LASTEST} 114 var tests = []string{ 115 "des3-cbc-sha1-kd", 116 "aes128-cts-hmac-sha1-96", 117 "aes256-cts-hmac-sha1-96", 118 "aes128-cts-hmac-sha256-128", 119 "aes256-cts-hmac-sha384-192", 120 "rc4-hmac", 121 } 122 for _, tst := range tests { 123 c.LibDefaults.DefaultTktEnctypes = []string{tst} 124 c.LibDefaults.DefaultTktEnctypeIDs = []int32{etypeID.ETypesByName[tst]} 125 c.LibDefaults.DefaultTGSEnctypes = []string{tst} 126 c.LibDefaults.DefaultTGSEnctypeIDs = []int32{etypeID.ETypesByName[tst]} 127 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 128 129 err := cl.Login() 130 if err != nil { 131 t.Errorf("error on login using enctype %s: %v\n", tst, err) 132 } 133 tkt, key, err := cl.GetServiceTicket("HTTP/host.test.gokrb5") 134 if err != nil { 135 t.Errorf("error in TGS exchange using enctype %s: %v", tst, err) 136 } 137 assert.Equal(t, "TEST.GOKRB5", tkt.Realm, "Realm in ticket not as expected for %s test", tst) 138 assert.Equal(t, etypeID.ETypesByName[tst], key.KeyType, "Key is not for enctype %s", tst) 139 } 140 } 141 142 func TestClient_ASExchange_TGSExchange_EncTypes_Password(t *testing.T) { 143 test.Integration(t) 144 145 c, _ := config.NewFromString(testdata.KRB5_CONF) 146 addr := os.Getenv("TEST_KDC_ADDR") 147 if addr == "" { 148 addr = testdata.KDC_IP_TEST_GOKRB5 149 } 150 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5_LASTEST} 151 var tests = []string{ 152 "des3-cbc-sha1-kd", 153 "aes128-cts-hmac-sha1-96", 154 "aes256-cts-hmac-sha1-96", 155 "aes128-cts-hmac-sha256-128", 156 "aes256-cts-hmac-sha384-192", 157 "rc4-hmac", 158 } 159 for _, tst := range tests { 160 c.LibDefaults.DefaultTktEnctypes = []string{tst} 161 c.LibDefaults.DefaultTktEnctypeIDs = []int32{etypeID.ETypesByName[tst]} 162 c.LibDefaults.DefaultTGSEnctypes = []string{tst} 163 c.LibDefaults.DefaultTGSEnctypeIDs = []int32{etypeID.ETypesByName[tst]} 164 cl := client.NewWithPassword("testuser1", "TEST.GOKRB5", "passwordvalue", c) 165 166 err := cl.Login() 167 if err != nil { 168 t.Errorf("error on login using enctype %s: %v\n", tst, err) 169 } 170 tkt, key, err := cl.GetServiceTicket("HTTP/host.test.gokrb5") 171 if err != nil { 172 t.Errorf("error in TGS exchange using enctype %s: %v", tst, err) 173 } 174 assert.Equal(t, "TEST.GOKRB5", tkt.Realm, "Realm in ticket not as expected for %s test", tst) 175 assert.Equal(t, etypeID.ETypesByName[tst], key.KeyType, "Key is not for enctype %s", tst) 176 } 177 } 178 179 func TestClient_FailedLogin(t *testing.T) { 180 test.Integration(t) 181 182 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5_WRONGPASSWD) 183 kt := keytab.New() 184 kt.Unmarshal(b) 185 c, _ := config.NewFromString(testdata.KRB5_CONF) 186 addr := os.Getenv("TEST_KDC_ADDR") 187 if addr == "" { 188 addr = testdata.KDC_IP_TEST_GOKRB5 189 } 190 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 191 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 192 193 err := cl.Login() 194 if err == nil { 195 t.Fatal("login with incorrect password did not error") 196 } 197 } 198 199 func TestClient_SuccessfulLogin_UserRequiringPreAuth(t *testing.T) { 200 test.Integration(t) 201 202 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER2_TEST_GOKRB5) 203 kt := keytab.New() 204 kt.Unmarshal(b) 205 c, _ := config.NewFromString(testdata.KRB5_CONF) 206 addr := os.Getenv("TEST_KDC_ADDR") 207 if addr == "" { 208 addr = testdata.KDC_IP_TEST_GOKRB5 209 } 210 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 211 cl := client.NewWithKeytab("testuser2", "TEST.GOKRB5", kt, c) 212 213 err := cl.Login() 214 if err != nil { 215 t.Fatalf("error on login: %v\n", err) 216 } 217 } 218 219 func TestClient_SuccessfulLogin_UserRequiringPreAuth_TCPOnly(t *testing.T) { 220 test.Integration(t) 221 222 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER2_TEST_GOKRB5) 223 kt := keytab.New() 224 kt.Unmarshal(b) 225 c, _ := config.NewFromString(testdata.KRB5_CONF) 226 addr := os.Getenv("TEST_KDC_ADDR") 227 if addr == "" { 228 addr = testdata.KDC_IP_TEST_GOKRB5 229 } 230 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 231 c.LibDefaults.UDPPreferenceLimit = 1 232 cl := client.NewWithKeytab("testuser2", "TEST.GOKRB5", kt, c) 233 234 err := cl.Login() 235 if err != nil { 236 t.Fatalf("error on login: %v\n", err) 237 } 238 } 239 240 func TestClient_NetworkTimeout(t *testing.T) { 241 test.Integration(t) 242 243 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 244 kt := keytab.New() 245 kt.Unmarshal(b) 246 c, _ := config.NewFromString(testdata.KRB5_CONF) 247 c.Realms[0].KDC = []string{testdata.KDC_IP_TEST_GOKRB5_BADADDR + ":88"} 248 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 249 250 err := cl.Login() 251 if err == nil { 252 t.Fatal("login with incorrect KDC address did not error") 253 } 254 } 255 256 func TestClient_NetworkTryNextKDC(t *testing.T) { 257 test.Integration(t) 258 259 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 260 kt := keytab.New() 261 kt.Unmarshal(b) 262 c, _ := config.NewFromString(testdata.KRB5_CONF) 263 addr := os.Getenv("TEST_KDC_ADDR") 264 if addr == "" { 265 addr = testdata.KDC_IP_TEST_GOKRB5 266 } 267 // Two out fo three times this should fail the first time. 268 // So will run login twice to expect at least once the first time it will be to a bad KDC 269 c.Realms[0].KDC = []string{testdata.KDC_IP_TEST_GOKRB5_BADADDR + ":88", 270 testdata.KDC_IP_TEST_GOKRB5_BADADDR + ":88", 271 addr + ":" + testdata.KDC_PORT_TEST_GOKRB5, 272 } 273 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 274 275 err := cl.Login() 276 if err != nil { 277 t.Fatal("login failed") 278 } 279 err = cl.Login() 280 if err != nil { 281 t.Fatal("login failed") 282 } 283 } 284 285 func TestClient_GetServiceTicket(t *testing.T) { 286 test.Integration(t) 287 288 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 289 kt := keytab.New() 290 kt.Unmarshal(b) 291 c, _ := config.NewFromString(testdata.KRB5_CONF) 292 addr := os.Getenv("TEST_KDC_ADDR") 293 if addr == "" { 294 addr = testdata.KDC_IP_TEST_GOKRB5 295 } 296 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 297 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 298 299 err := cl.Login() 300 if err != nil { 301 t.Fatalf("error on login: %v\n", err) 302 } 303 spn := "HTTP/host.test.gokrb5" 304 tkt, key, err := cl.GetServiceTicket(spn) 305 if err != nil { 306 t.Fatalf("error getting service ticket: %v\n", err) 307 } 308 assert.Equal(t, spn, tkt.SName.PrincipalNameString()) 309 assert.Equal(t, int32(18), key.KeyType) 310 311 //Check cache use - should get the same values back again 312 tkt2, key2, err := cl.GetServiceTicket(spn) 313 if err != nil { 314 t.Fatalf("error getting service ticket: %v\n", err) 315 } 316 assert.Equal(t, tkt.EncPart.Cipher, tkt2.EncPart.Cipher) 317 assert.Equal(t, key.KeyValue, key2.KeyValue) 318 } 319 320 func TestClient_GetServiceTicket_CanonicalizeTrue(t *testing.T) { 321 test.Integration(t) 322 323 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 324 kt := keytab.New() 325 kt.Unmarshal(b) 326 c, _ := config.NewFromString(testdata.KRB5_CONF) 327 c.LibDefaults.Canonicalize = true 328 addr := os.Getenv("TEST_KDC_ADDR") 329 if addr == "" { 330 addr = testdata.KDC_IP_TEST_GOKRB5 331 } 332 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 333 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 334 335 err := cl.Login() 336 if err != nil { 337 t.Fatalf("error on login: %v\n", err) 338 } 339 spn := "HTTP/host.test.gokrb5" 340 tkt, key, err := cl.GetServiceTicket(spn) 341 if err != nil { 342 t.Fatalf("error getting service ticket: %v\n", err) 343 } 344 assert.Equal(t, spn, tkt.SName.PrincipalNameString()) 345 assert.Equal(t, int32(18), key.KeyType) 346 347 //Check cache use - should get the same values back again 348 tkt2, key2, err := cl.GetServiceTicket(spn) 349 if err != nil { 350 t.Fatalf("error getting service ticket: %v\n", err) 351 } 352 assert.Equal(t, tkt.EncPart.Cipher, tkt2.EncPart.Cipher) 353 assert.Equal(t, key.KeyValue, key2.KeyValue) 354 } 355 356 func TestClient_GetServiceTicket_InvalidSPN(t *testing.T) { 357 test.Integration(t) 358 359 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 360 kt := keytab.New() 361 kt.Unmarshal(b) 362 c, _ := config.NewFromString(testdata.KRB5_CONF) 363 addr := os.Getenv("TEST_KDC_ADDR") 364 if addr == "" { 365 addr = testdata.KDC_IP_TEST_GOKRB5 366 } 367 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 368 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 369 370 err := cl.Login() 371 if err != nil { 372 t.Fatalf("error on login: %v\n", err) 373 } 374 spn := "host.test.gokrb5" 375 _, _, err = cl.GetServiceTicket(spn) 376 assert.NotNil(t, err, "Expected unknown principal error") 377 assert.True(t, strings.Contains(err.Error(), "KDC_ERR_S_PRINCIPAL_UNKNOWN"), "Error text not as expected") 378 } 379 380 func TestClient_GetServiceTicket_OlderKDC(t *testing.T) { 381 test.Integration(t) 382 383 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 384 kt := keytab.New() 385 kt.Unmarshal(b) 386 c, _ := config.NewFromString(testdata.KRB5_CONF) 387 addr := os.Getenv("TEST_KDC_ADDR") 388 if addr == "" { 389 addr = testdata.KDC_IP_TEST_GOKRB5 390 } 391 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5_OLD} 392 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 393 394 err := cl.Login() 395 if err != nil { 396 t.Fatalf("error on login: %v\n", err) 397 } 398 spn := "HTTP/host.test.gokrb5" 399 tkt, key, err := cl.GetServiceTicket(spn) 400 if err != nil { 401 t.Fatalf("error getting service ticket: %v\n", err) 402 } 403 assert.Equal(t, spn, tkt.SName.PrincipalNameString()) 404 assert.Equal(t, int32(18), key.KeyType) 405 } 406 407 func TestMultiThreadedClientUse(t *testing.T) { 408 test.Integration(t) 409 410 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 411 kt := keytab.New() 412 kt.Unmarshal(b) 413 c, _ := config.NewFromString(testdata.KRB5_CONF) 414 addr := os.Getenv("TEST_KDC_ADDR") 415 if addr == "" { 416 addr = testdata.KDC_IP_TEST_GOKRB5 417 } 418 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 419 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 420 421 var wg sync.WaitGroup 422 wg.Add(5) 423 for i := 0; i < 5; i++ { 424 go func() { 425 defer wg.Done() 426 err := cl.Login() 427 if err != nil { 428 panic(err) 429 } 430 }() 431 } 432 wg.Wait() 433 434 var wg2 sync.WaitGroup 435 wg2.Add(5) 436 for i := 0; i < 5; i++ { 437 go func() { 438 defer wg2.Done() 439 err := spnegoGet(cl) 440 if err != nil { 441 panic(err) 442 } 443 }() 444 } 445 wg2.Wait() 446 } 447 448 func spnegoGet(cl *client.Client) error { 449 url := os.Getenv("TEST_HTTP_URL") 450 if url == "" { 451 url = testdata.TEST_HTTP_URL 452 } 453 r, _ := http.NewRequest("GET", url+"/modgssapi/index.html", nil) 454 httpResp, err := http.DefaultClient.Do(r) 455 if err != nil { 456 return fmt.Errorf("request error: %v\n", err) 457 } 458 if httpResp.StatusCode != http.StatusUnauthorized { 459 return errors.New("did not get unauthorized code when no SPNEGO header set") 460 } 461 err = spnego.SetSPNEGOHeader(cl, r, "HTTP/host.test.gokrb5") 462 if err != nil { 463 return fmt.Errorf("error setting client SPNEGO header: %v", err) 464 } 465 httpResp, err = http.DefaultClient.Do(r) 466 if err != nil { 467 return fmt.Errorf("request error: %v\n", err) 468 } 469 if httpResp.StatusCode != http.StatusOK { 470 return errors.New("did not get OK code when SPNEGO header set") 471 } 472 return nil 473 } 474 475 func TestNewFromCCache(t *testing.T) { 476 test.Integration(t) 477 478 b, err := hex.DecodeString(testdata.CCACHE_TEST) 479 if err != nil { 480 t.Fatalf("error decoding test data") 481 } 482 cc := new(credentials.CCache) 483 err = cc.Unmarshal(b) 484 if err != nil { 485 t.Fatal("error getting test CCache") 486 } 487 c, _ := config.NewFromString(testdata.KRB5_CONF) 488 addr := os.Getenv("TEST_KDC_ADDR") 489 if addr == "" { 490 addr = testdata.KDC_IP_TEST_GOKRB5 491 } 492 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 493 cl, err := client.NewFromCCache(cc, c) 494 if err != nil { 495 t.Fatalf("error creating client from CCache: %v", err) 496 } 497 if ok, err := cl.IsConfigured(); !ok { 498 t.Fatalf("client was not configured from CCache: %v", err) 499 } 500 } 501 502 // Login to the TEST.GOKRB5 domain and request service ticket for resource in the RESDOM.GOKRB5 domain. 503 // There is a trust between the two domains. 504 func TestClient_GetServiceTicket_Trusted_Resource_Domain(t *testing.T) { 505 test.Integration(t) 506 507 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 508 kt := keytab.New() 509 kt.Unmarshal(b) 510 c, _ := config.NewFromString(testdata.KRB5_CONF) 511 512 addr := os.Getenv("TEST_KDC_ADDR") 513 if addr == "" { 514 addr = testdata.KDC_IP_TEST_GOKRB5 515 } 516 for i, r := range c.Realms { 517 if r.Realm == "TEST.GOKRB5" { 518 c.Realms[i].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 519 } 520 if r.Realm == "RESDOM.GOKRB5" { 521 c.Realms[i].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5_RESDOM} 522 } 523 } 524 525 c.LibDefaults.DefaultRealm = "TEST.GOKRB5" 526 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 527 c.LibDefaults.DefaultTktEnctypes = []string{"aes256-cts-hmac-sha1-96"} 528 c.LibDefaults.DefaultTktEnctypeIDs = []int32{etypeID.ETypesByName["aes256-cts-hmac-sha1-96"]} 529 c.LibDefaults.DefaultTGSEnctypes = []string{"aes256-cts-hmac-sha1-96"} 530 c.LibDefaults.DefaultTGSEnctypeIDs = []int32{etypeID.ETypesByName["aes256-cts-hmac-sha1-96"]} 531 532 err := cl.Login() 533 534 if err != nil { 535 t.Fatalf("error on login: %v\n", err) 536 } 537 spn := "HTTP/host.resdom.gokrb5" 538 tkt, key, err := cl.GetServiceTicket(spn) 539 if err != nil { 540 t.Fatalf("error getting service ticket: %v\n", err) 541 } 542 assert.Equal(t, spn, tkt.SName.PrincipalNameString()) 543 assert.Equal(t, etypeID.ETypesByName["aes256-cts-hmac-sha1-96"], key.KeyType) 544 545 b, _ = hex.DecodeString(testdata.KEYTAB_SYSHTTP_RESDOM_GOKRB5) 546 skt := keytab.New() 547 skt.Unmarshal(b) 548 err = tkt.DecryptEncPart(skt, nil) 549 if err != nil { 550 t.Errorf("error decrypting ticket with service keytab: %v", err) 551 } 552 } 553 554 const ( 555 kinitCmd = "kinit" 556 kvnoCmd = "kvno" 557 spn = "HTTP/host.test.gokrb5" 558 ) 559 560 func login() error { 561 file, err := os.Create("/etc/krb5.conf") 562 if err != nil { 563 return fmt.Errorf("cannot open krb5.conf: %v", err) 564 } 565 defer file.Close() 566 fmt.Fprintf(file, testdata.KRB5_CONF) 567 568 cmd := exec.Command(kinitCmd, "testuser1@TEST.GOKRB5") 569 570 stdinR, stdinW := io.Pipe() 571 stderrR, stderrW := io.Pipe() 572 cmd.Stdin = stdinR 573 cmd.Stderr = stderrW 574 575 err = cmd.Start() 576 if err != nil { 577 return fmt.Errorf("could not start %s command: %v", kinitCmd, err) 578 } 579 580 go func() { 581 io.WriteString(stdinW, "passwordvalue") 582 stdinW.Close() 583 }() 584 errBuf := new(bytes.Buffer) 585 go func() { 586 io.Copy(errBuf, stderrR) 587 stderrR.Close() 588 }() 589 590 err = cmd.Wait() 591 if err != nil { 592 return fmt.Errorf("%s did not run successfully: %v stderr: %s", kinitCmd, err, string(errBuf.Bytes())) 593 } 594 return nil 595 } 596 597 func getServiceTkt() error { 598 cmd := exec.Command(kvnoCmd, spn) 599 err := cmd.Start() 600 if err != nil { 601 return fmt.Errorf("could not start %s command: %v", kvnoCmd, err) 602 } 603 err = cmd.Wait() 604 if err != nil { 605 return fmt.Errorf("%s did not run successfully: %v", kvnoCmd, err) 606 } 607 return nil 608 } 609 610 func loadCCache() (*credentials.CCache, error) { 611 usr, _ := user.Current() 612 cpath := "/tmp/krb5cc_" + usr.Uid 613 return credentials.LoadCCache(cpath) 614 } 615 616 func TestGetServiceTicketFromCCacheTGT(t *testing.T) { 617 test.Privileged(t) 618 619 err := login() 620 if err != nil { 621 t.Fatalf("error logging in with kinit: %v", err) 622 } 623 c, err := loadCCache() 624 if err != nil { 625 t.Errorf("error loading CCache: %v", err) 626 } 627 cfg, _ := config.NewFromString(testdata.KRB5_CONF) 628 addr := os.Getenv("TEST_KDC_ADDR") 629 if addr == "" { 630 addr = testdata.KDC_IP_TEST_GOKRB5 631 } 632 cfg.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 633 cl, err := client.NewFromCCache(c, cfg) 634 if err != nil { 635 t.Fatalf("error generating client from ccache: %v", err) 636 } 637 spn := "HTTP/host.test.gokrb5" 638 tkt, key, err := cl.GetServiceTicket(spn) 639 if err != nil { 640 t.Fatalf("error getting service ticket: %v\n", err) 641 } 642 assert.Equal(t, spn, tkt.SName.PrincipalNameString()) 643 assert.Equal(t, int32(18), key.KeyType) 644 645 //Check cache use - should get the same values back again 646 tkt2, key2, err := cl.GetServiceTicket(spn) 647 if err != nil { 648 t.Fatalf("error getting service ticket: %v\n", err) 649 } 650 assert.Equal(t, tkt.EncPart.Cipher, tkt2.EncPart.Cipher) 651 assert.Equal(t, key.KeyValue, key2.KeyValue) 652 653 url := os.Getenv("TEST_HTTP_URL") 654 if url == "" { 655 url = testdata.TEST_HTTP_URL 656 } 657 r, _ := http.NewRequest("GET", url+"/modgssapi/index.html", nil) 658 err = spnego.SetSPNEGOHeader(cl, r, "HTTP/host.test.gokrb5") 659 if err != nil { 660 t.Fatalf("error setting client SPNEGO header: %v", err) 661 } 662 httpResp, err := http.DefaultClient.Do(r) 663 if err != nil { 664 t.Fatalf("request error: %v\n", err) 665 } 666 assert.Equal(t, http.StatusOK, httpResp.StatusCode, "status code in response to client SPNEGO request not as expected") 667 } 668 669 func TestGetServiceTicketFromCCacheWithoutKDC(t *testing.T) { 670 test.Privileged(t) 671 672 err := login() 673 if err != nil { 674 t.Fatalf("error logging in with kinit: %v", err) 675 } 676 err = getServiceTkt() 677 if err != nil { 678 t.Fatalf("error getting service ticket: %v", err) 679 } 680 c, err := loadCCache() 681 if err != nil { 682 t.Errorf("error loading CCache: %v", err) 683 } 684 cfg, _ := config.NewFromString("...") 685 cl, err := client.NewFromCCache(c, cfg) 686 if err != nil { 687 t.Fatalf("error generating client from ccache: %v", err) 688 } 689 url := os.Getenv("TEST_HTTP_URL") 690 if url == "" { 691 url = testdata.TEST_HTTP_URL 692 } 693 r, _ := http.NewRequest("GET", url+"/modgssapi/index.html", nil) 694 err = spnego.SetSPNEGOHeader(cl, r, "HTTP/host.test.gokrb5") 695 if err != nil { 696 t.Fatalf("error setting client SPNEGO header: %v", err) 697 } 698 httpResp, err := http.DefaultClient.Do(r) 699 if err != nil { 700 t.Fatalf("request error: %v\n", err) 701 } 702 assert.Equal(t, http.StatusOK, httpResp.StatusCode, "status code in response to client SPNEGO request not as expected") 703 } 704 705 func TestClient_ChangePasswd(t *testing.T) { 706 test.Integration(t) 707 708 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 709 kt := keytab.New() 710 kt.Unmarshal(b) 711 c, _ := config.NewFromString(testdata.KRB5_CONF) 712 addr := os.Getenv("TEST_KDC_ADDR") 713 if addr == "" { 714 addr = testdata.KDC_IP_TEST_GOKRB5 715 } 716 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5} 717 c.Realms[0].KPasswdServer = []string{addr + ":464"} 718 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 719 720 ok, err := cl.ChangePasswd("newpassword") 721 if err != nil { 722 t.Fatalf("error changing password: %v", err) 723 } 724 assert.True(t, ok, "password was not changed") 725 726 cl = client.NewWithPassword("testuser1", "TEST.GOKRB5", "newpassword", c) 727 ok, err = cl.ChangePasswd(testdata.TESTUSER_PASSWORD) 728 if err != nil { 729 t.Fatalf("error changing password: %v", err) 730 } 731 assert.True(t, ok, "password was not changed back") 732 733 cl = client.NewWithPassword("testuser1", "TEST.GOKRB5", testdata.TESTUSER_PASSWORD, c) 734 err = cl.Login() 735 if err != nil { 736 t.Fatalf("Could not log back in after reverting password: %v", err) 737 } 738 } 739 740 func TestClient_Destroy(t *testing.T) { 741 test.Integration(t) 742 743 addr := os.Getenv("TEST_KDC_ADDR") 744 if addr == "" { 745 addr = testdata.KDC_IP_TEST_GOKRB5 746 } 747 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 748 kt := keytab.New() 749 kt.Unmarshal(b) 750 c, _ := config.NewFromString(testdata.KRB5_CONF) 751 c.Realms[0].KDC = []string{addr + ":" + testdata.KDC_PORT_TEST_GOKRB5_SHORTTICKETS} 752 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 753 754 err := cl.Login() 755 if err != nil { 756 t.Fatalf("error on login: %v\n", err) 757 } 758 spn := "HTTP/host.test.gokrb5" 759 _, _, err = cl.GetServiceTicket(spn) 760 if err != nil { 761 t.Fatalf("error getting service ticket: %v\n", err) 762 } 763 n := runtime.NumGoroutine() 764 time.Sleep(time.Second * 60) 765 cl.Destroy() 766 time.Sleep(time.Second * 5) 767 assert.True(t, runtime.NumGoroutine() < n, "auto-renewal goroutine was not stopped when client destroyed") 768 is, _ := cl.IsConfigured() 769 assert.False(t, is, "client is still configured after it was destroyed") 770 }