client_integration_test.go 21 KB

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