client_integration_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. // +build integration
  2. // To turn on this test use -tags=integration in go test command
  3. package client
  4. import (
  5. "encoding/hex"
  6. "github.com/stretchr/testify/assert"
  7. "gopkg.in/jcmturner/gokrb5.v2/config"
  8. "gopkg.in/jcmturner/gokrb5.v2/credentials"
  9. "gopkg.in/jcmturner/gokrb5.v2/iana/etypeID"
  10. "gopkg.in/jcmturner/gokrb5.v2/keytab"
  11. "gopkg.in/jcmturner/gokrb5.v2/testdata"
  12. "net/http"
  13. "os"
  14. "testing"
  15. )
  16. func TestClient_SuccessfulLogin_Keytab(t *testing.T) {
  17. addr := os.Getenv("TEST_KDC_ADDR")
  18. if addr == "" {
  19. addr = testdata.TEST_KDC_ADDR
  20. }
  21. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  22. kt, _ := keytab.Parse(b)
  23. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  24. var tests = []string{
  25. testdata.TEST_KDC,
  26. testdata.TEST_KDC_OLD,
  27. testdata.TEST_KDC_LASTEST,
  28. }
  29. for _, test := range tests {
  30. c.Realms[0].KDC = []string{addr + ":" + test}
  31. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  32. cl.WithConfig(c)
  33. err = cl.Login()
  34. if err != nil {
  35. t.Errorf("Error on logging in with KDC %s: %v\n", test, err)
  36. }
  37. }
  38. }
  39. func TestClient_SuccessfulLogin_Password(t *testing.T) {
  40. addr := os.Getenv("TEST_KDC_ADDR")
  41. if addr == "" {
  42. addr = testdata.TEST_KDC_ADDR
  43. }
  44. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  45. var tests = []string{
  46. testdata.TEST_KDC,
  47. testdata.TEST_KDC_OLD,
  48. testdata.TEST_KDC_LASTEST,
  49. }
  50. for _, test := range tests {
  51. c.Realms[0].KDC = []string{addr + ":" + test}
  52. cl := NewClientWithPassword("testuser1", "TESTGOKRB5", "passwordvalue")
  53. cl.WithConfig(c)
  54. err := cl.Login()
  55. if err != nil {
  56. t.Errorf("Error on logging in with KDC %s: %v\n", test, err)
  57. }
  58. }
  59. }
  60. func TestClient_SuccessfulLogin_TCPOnly(t *testing.T) {
  61. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  62. kt, _ := keytab.Parse(b)
  63. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  64. addr := os.Getenv("TEST_KDC_ADDR")
  65. if addr == "" {
  66. addr = testdata.TEST_KDC_ADDR
  67. }
  68. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  69. c.LibDefaults.UDPPreferenceLimit = 1
  70. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  71. cl.WithConfig(c)
  72. err = cl.Login()
  73. if err != nil {
  74. t.Fatalf("Error on login: %v\n", err)
  75. }
  76. }
  77. func TestClient_ASExchange_TGSExchange_EncTypes_Keytab(t *testing.T) {
  78. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  79. kt, _ := keytab.Parse(b)
  80. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  81. addr := os.Getenv("TEST_KDC_ADDR")
  82. if addr == "" {
  83. addr = testdata.TEST_KDC_ADDR
  84. }
  85. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC_LASTEST}
  86. var tests = []string{
  87. "des3-cbc-sha1-kd",
  88. "aes128-cts-hmac-sha1-96",
  89. "aes256-cts-hmac-sha1-96",
  90. "aes128-cts-hmac-sha256-128",
  91. "aes256-cts-hmac-sha384-192",
  92. "rc4-hmac",
  93. }
  94. for _, test := range tests {
  95. c.LibDefaults.DefaultTktEnctypes = []string{test}
  96. c.LibDefaults.DefaultTktEnctypeIDs = []int{etypeID.ETypesByName[test]}
  97. c.LibDefaults.DefaultTGSEnctypes = []string{test}
  98. c.LibDefaults.DefaultTGSEnctypeIDs = []int{etypeID.ETypesByName[test]}
  99. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  100. cl.WithConfig(c)
  101. err = cl.Login()
  102. if err != nil {
  103. t.Errorf("Error on login using enctype %s: %v\n", test, err)
  104. }
  105. tkt, key, err := cl.GetServiceTicket("HTTP/host.test.gokrb5")
  106. if err != nil {
  107. t.Errorf("Error in TGS exchange using enctype %s: %v", test, err)
  108. }
  109. assert.Equal(t, "TEST.GOKRB5", tkt.Realm, "Realm in ticket not as expected for %s test", test)
  110. assert.Equal(t, etypeID.ETypesByName[test], key.KeyType, "Key is not for enctype %s", test)
  111. }
  112. }
  113. func TestClient_ASExchange_TGSExchange_EncTypes_Password(t *testing.T) {
  114. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  115. addr := os.Getenv("TEST_KDC_ADDR")
  116. if addr == "" {
  117. addr = testdata.TEST_KDC_ADDR
  118. }
  119. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC_LASTEST}
  120. var tests = []string{
  121. "des3-cbc-sha1-kd",
  122. "aes128-cts-hmac-sha1-96",
  123. "aes256-cts-hmac-sha1-96",
  124. "aes128-cts-hmac-sha256-128",
  125. "aes256-cts-hmac-sha384-192",
  126. "rc4-hmac",
  127. }
  128. for _, test := range tests {
  129. c.LibDefaults.DefaultTktEnctypes = []string{test}
  130. c.LibDefaults.DefaultTktEnctypeIDs = []int{etypeID.ETypesByName[test]}
  131. c.LibDefaults.DefaultTGSEnctypes = []string{test}
  132. c.LibDefaults.DefaultTGSEnctypeIDs = []int{etypeID.ETypesByName[test]}
  133. cl := NewClientWithPassword("testuser1", "TESTGOKRB5", "passwordvalue")
  134. cl.WithConfig(c)
  135. err := cl.Login()
  136. if err != nil {
  137. t.Errorf("Error on login using enctype %s: %v\n", test, err)
  138. }
  139. tkt, key, err := cl.GetServiceTicket("HTTP/host.test.gokrb5")
  140. if err != nil {
  141. t.Errorf("Error in TGS exchange using enctype %s: %v", test, err)
  142. }
  143. assert.Equal(t, "TEST.GOKRB5", tkt.Realm, "Realm in ticket not as expected for %s test", test)
  144. assert.Equal(t, etypeID.ETypesByName[test], key.KeyType, "Key is not for enctype %s", test)
  145. }
  146. }
  147. func TestClient_FailedLogin(t *testing.T) {
  148. b, err := hex.DecodeString(testdata.TESTUSER1_WRONGPASSWD)
  149. kt, _ := keytab.Parse(b)
  150. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  151. addr := os.Getenv("TEST_KDC_ADDR")
  152. if addr == "" {
  153. addr = testdata.TEST_KDC_ADDR
  154. }
  155. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  156. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  157. cl.WithConfig(c)
  158. err = cl.Login()
  159. if err == nil {
  160. t.Fatal("Login with incorrect password did not error")
  161. }
  162. }
  163. func TestClient_SuccessfulLogin_UserRequiringPreAuth(t *testing.T) {
  164. b, err := hex.DecodeString(testdata.TESTUSER2_KEYTAB)
  165. kt, _ := keytab.Parse(b)
  166. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  167. addr := os.Getenv("TEST_KDC_ADDR")
  168. if addr == "" {
  169. addr = testdata.TEST_KDC_ADDR
  170. }
  171. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  172. cl := NewClientWithKeytab("testuser2", "TEST.GOKRB5", kt)
  173. cl.WithConfig(c)
  174. err = cl.Login()
  175. if err != nil {
  176. t.Fatalf("Error on login: %v\n", err)
  177. }
  178. }
  179. func TestClient_SuccessfulLogin_UserRequiringPreAuth_TCPOnly(t *testing.T) {
  180. b, err := hex.DecodeString(testdata.TESTUSER2_KEYTAB)
  181. kt, _ := keytab.Parse(b)
  182. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  183. addr := os.Getenv("TEST_KDC_ADDR")
  184. if addr == "" {
  185. addr = testdata.TEST_KDC_ADDR
  186. }
  187. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  188. c.LibDefaults.UDPPreferenceLimit = 1
  189. cl := NewClientWithKeytab("testuser2", "TEST.GOKRB5", kt)
  190. cl.WithConfig(c)
  191. err = cl.Login()
  192. if err != nil {
  193. t.Fatalf("Error on login: %v\n", err)
  194. }
  195. }
  196. func TestClient_NetworkTimeout(t *testing.T) {
  197. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  198. kt, _ := keytab.Parse(b)
  199. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  200. c.Realms[0].KDC = []string{testdata.TEST_KDC_BADADDR + ":88"}
  201. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  202. cl.WithConfig(c)
  203. err = cl.Login()
  204. if err == nil {
  205. t.Fatal("Login with incorrect KDC address did not error")
  206. }
  207. }
  208. func TestClient_GetServiceTicket(t *testing.T) {
  209. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  210. kt, _ := keytab.Parse(b)
  211. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  212. addr := os.Getenv("TEST_KDC_ADDR")
  213. if addr == "" {
  214. addr = testdata.TEST_KDC_ADDR
  215. }
  216. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  217. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  218. cl.WithConfig(c)
  219. err = cl.Login()
  220. if err != nil {
  221. t.Fatalf("Error on login: %v\n", err)
  222. }
  223. spn := "HTTP/host.test.gokrb5"
  224. tkt, key, err := cl.GetServiceTicket(spn)
  225. if err != nil {
  226. t.Fatalf("Error getting service ticket: %v\n", err)
  227. }
  228. assert.Equal(t, spn, tkt.SName.GetPrincipalNameString())
  229. assert.Equal(t, 18, key.KeyType)
  230. //Check cache use - should get the same values back again
  231. tkt2, key2, err := cl.GetServiceTicket(spn)
  232. if err != nil {
  233. t.Fatalf("Error getting service ticket: %v\n", err)
  234. }
  235. assert.Equal(t, tkt.EncPart.Cipher, tkt2.EncPart.Cipher)
  236. assert.Equal(t, key.KeyValue, key2.KeyValue)
  237. }
  238. func TestClient_GetServiceTicket_OlderKDC(t *testing.T) {
  239. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  240. kt, _ := keytab.Parse(b)
  241. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  242. addr := os.Getenv("TEST_KDC_ADDR")
  243. if addr == "" {
  244. addr = testdata.TEST_KDC_ADDR
  245. }
  246. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC_OLD}
  247. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  248. cl.WithConfig(c)
  249. err = cl.Login()
  250. if err != nil {
  251. t.Fatalf("Error on login: %v\n", err)
  252. }
  253. spn := "HTTP/host.test.gokrb5"
  254. tkt, key, err := cl.GetServiceTicket(spn)
  255. if err != nil {
  256. t.Fatalf("Error getting service ticket: %v\n", err)
  257. }
  258. assert.Equal(t, spn, tkt.SName.GetPrincipalNameString())
  259. assert.Equal(t, 18, key.KeyType)
  260. }
  261. func TestClient_SetSPNEGOHeader(t *testing.T) {
  262. b, _ := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  263. kt, _ := keytab.Parse(b)
  264. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  265. addr := os.Getenv("TEST_KDC_ADDR")
  266. if addr == "" {
  267. addr = testdata.TEST_KDC_ADDR
  268. }
  269. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  270. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  271. cl.WithConfig(c)
  272. err := cl.Login()
  273. if err != nil {
  274. t.Fatalf("Error on AS_REQ: %v\n", err)
  275. }
  276. url := os.Getenv("TEST_HTTP_URL")
  277. if url == "" {
  278. url = testdata.TEST_HTTP_URL
  279. }
  280. r, _ := http.NewRequest("GET", url, nil)
  281. httpResp, err := http.DefaultClient.Do(r)
  282. if err != nil {
  283. t.Fatalf("Request error: %v\n", err)
  284. }
  285. assert.Equal(t, http.StatusUnauthorized, httpResp.StatusCode, "Status code in response to client with no SPNEGO not as expected")
  286. err = cl.SetSPNEGOHeader(r, "HTTP/host.test.gokrb5")
  287. if err != nil {
  288. t.Fatalf("Error setting client SPNEGO header: %v", err)
  289. }
  290. httpResp, err = http.DefaultClient.Do(r)
  291. if err != nil {
  292. t.Fatalf("Request error: %v\n", err)
  293. }
  294. assert.Equal(t, http.StatusOK, httpResp.StatusCode, "Status code in response to client SPNEGO request not as expected")
  295. }
  296. func TestMultiThreadedClientUse(t *testing.T) {
  297. b, _ := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  298. kt, _ := keytab.Parse(b)
  299. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  300. addr := os.Getenv("TEST_KDC_ADDR")
  301. if addr == "" {
  302. addr = testdata.TEST_KDC_ADDR
  303. }
  304. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  305. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  306. cl.WithConfig(c)
  307. for i := 0; i < 5; i++ {
  308. go login(t, &cl)
  309. }
  310. for i := 0; i < 5; i++ {
  311. go spnegoGet(t, &cl)
  312. }
  313. }
  314. func login(t *testing.T, cl *Client) {
  315. err := cl.Login()
  316. if err != nil {
  317. t.Fatalf("Error on AS_REQ: %v\n", err)
  318. }
  319. }
  320. func spnegoGet(t *testing.T, cl *Client) {
  321. url := os.Getenv("TEST_HTTP_URL")
  322. if url == "" {
  323. url = testdata.TEST_HTTP_URL
  324. }
  325. r, _ := http.NewRequest("GET", url, nil)
  326. httpResp, err := http.DefaultClient.Do(r)
  327. if err != nil {
  328. t.Fatalf("Request error: %v\n", err)
  329. }
  330. assert.Equal(t, http.StatusUnauthorized, httpResp.StatusCode, "Status code in response to client with no SPNEGO not as expected")
  331. err = cl.SetSPNEGOHeader(r, "HTTP/host.test.gokrb5")
  332. if err != nil {
  333. t.Fatalf("Error setting client SPNEGO header: %v", err)
  334. }
  335. httpResp, err = http.DefaultClient.Do(r)
  336. if err != nil {
  337. t.Fatalf("Request error: %v\n", err)
  338. }
  339. assert.Equal(t, http.StatusOK, httpResp.StatusCode, "Status code in response to client SPNEGO request not as expected")
  340. }
  341. func TestNewClientFromCCache(t *testing.T) {
  342. b, err := hex.DecodeString(testdata.CCACHE_TEST)
  343. if err != nil {
  344. t.Fatalf("Error decoding test data")
  345. }
  346. cc, err := credentials.ParseCCache(b)
  347. if err != nil {
  348. t.Fatal("Error getting test CCache")
  349. }
  350. cl, err := NewClientFromCCache(cc)
  351. if err != nil {
  352. t.Fatalf("Error creating client from CCache: %v", err)
  353. }
  354. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  355. addr := os.Getenv("TEST_KDC_ADDR")
  356. if addr == "" {
  357. addr = testdata.TEST_KDC_ADDR
  358. }
  359. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  360. cl.WithConfig(c)
  361. if ok, err := cl.IsConfigured(); !ok {
  362. t.Fatalf("Client was not configured from CCache: %v", err)
  363. }
  364. }
  365. func TestResolveKDC(t *testing.T) {
  366. //ns := os.Getenv("DNSUTILS_OVERRIDE_NS")
  367. //if ns == "" {
  368. // os.Setenv("DNSUTILS_OVERRIDE_NS", testdata.TEST_NS)
  369. //}
  370. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  371. c.LibDefaults.DNSLookupKDC = true
  372. var cl Client
  373. cl.WithConfig(c)
  374. count, res, err := cl.resolveKDC(c.LibDefaults.DefaultRealm, true)
  375. if err != nil {
  376. t.Errorf("error resolving KDC via DNS TCP: %v", err)
  377. }
  378. assert.Equal(t, 5, count, "Number of SRV records not as expected: %v", res)
  379. assert.Equal(t, count, len(res), "Map size does not match: %v", res)
  380. t.Logf("res: %v", res)
  381. expected := []string{
  382. "kdc.test.gokrb5:88",
  383. "kdc1a.test.gokrb5:88",
  384. "kdc2a.test.gokrb5:88",
  385. "kdc1b.test.gokrb5:88",
  386. "kdc2b.test.gokrb5:88",
  387. }
  388. for _, s := range expected {
  389. var found bool
  390. for _, v := range res {
  391. if s == v {
  392. found = true
  393. break
  394. }
  395. }
  396. assert.True(t, found, "Record %s not found in results", s)
  397. }
  398. c.LibDefaults.DNSLookupKDC = false
  399. _, res, err = cl.resolveKDC(c.LibDefaults.DefaultRealm, true)
  400. if err != nil {
  401. t.Errorf("error resolving KDCs from config: %v", err)
  402. }
  403. assert.Equal(t, "127.0.0.1:88", res[1], "KDC not read from config as expected")
  404. }
  405. func TestClient_Login_DNSKDCs(t *testing.T) {
  406. //ns := os.Getenv("DNSUTILS_OVERRIDE_NS")
  407. //if ns == "" {
  408. // os.Setenv("DNSUTILS_OVERRIDE_NS", testdata.TEST_NS)
  409. //}
  410. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  411. // Set to lookup KDCs in DNS
  412. c.LibDefaults.DNSLookupKDC = true
  413. //Blank out the KDCs to ensure they are not being used
  414. c.Realms = []config.Realm{}
  415. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  416. kt, _ := keytab.Parse(b)
  417. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  418. cl.WithConfig(c)
  419. err = cl.Login()
  420. if err != nil {
  421. t.Errorf("Error on logging in using DNS lookup of KDCs: %v\n", err)
  422. }
  423. }