client_integration_test.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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(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_TCPOnly(t *testing.T) {
  40. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  41. kt, _ := keytab.Parse(b)
  42. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  43. addr := os.Getenv("TEST_KDC_ADDR")
  44. if addr == "" {
  45. addr = testdata.TEST_KDC_ADDR
  46. }
  47. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  48. c.LibDefaults.UDPPreferenceLimit = 1
  49. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  50. cl.WithConfig(c)
  51. err = cl.Login()
  52. if err != nil {
  53. t.Fatalf("Error on login: %v\n", err)
  54. }
  55. }
  56. func TestClient_ASExchange_TGSExchange_EncTypes(t *testing.T) {
  57. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  58. kt, _ := keytab.Parse(b)
  59. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  60. addr := os.Getenv("TEST_KDC_ADDR")
  61. if addr == "" {
  62. addr = testdata.TEST_KDC_ADDR
  63. }
  64. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC_LASTEST}
  65. var tests = []string{
  66. "des3-cbc-sha1-kd",
  67. "aes128-cts-hmac-sha1-96",
  68. "aes256-cts-hmac-sha1-96",
  69. "aes128-cts-hmac-sha256-128",
  70. "aes256-cts-hmac-sha384-192",
  71. "rc4-hmac",
  72. }
  73. for _, test := range tests {
  74. c.LibDefaults.DefaultTktEnctypes = []string{test}
  75. c.LibDefaults.DefaultTktEnctypeIDs = []int{etypeID.ETypesByName[test]}
  76. c.LibDefaults.DefaultTGSEnctypes = []string{test}
  77. c.LibDefaults.DefaultTGSEnctypeIDs = []int{etypeID.ETypesByName[test]}
  78. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  79. cl.WithConfig(c)
  80. err = cl.Login()
  81. if err != nil {
  82. t.Errorf("Error on login using enctype %s: %v\n", test, err)
  83. }
  84. tkt, key, err := cl.GetServiceTicket("HTTP/host.test.gokrb5")
  85. if err != nil {
  86. t.Errorf("Error in TGS exchange using enctype %s: %v", test, err)
  87. }
  88. assert.Equal(t, "TEST.GOKRB5", tkt.Realm, "Realm in ticket not as expected for %s test", test)
  89. assert.Equal(t, etypeID.ETypesByName[test], key.KeyType, "Key is not for enctype %s", test)
  90. }
  91. }
  92. func TestClient_FailedLogin(t *testing.T) {
  93. b, err := hex.DecodeString(testdata.TESTUSER1_WRONGPASSWD)
  94. kt, _ := keytab.Parse(b)
  95. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  96. addr := os.Getenv("TEST_KDC_ADDR")
  97. if addr == "" {
  98. addr = testdata.TEST_KDC_ADDR
  99. }
  100. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  101. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  102. cl.WithConfig(c)
  103. err = cl.Login()
  104. if err == nil {
  105. t.Fatal("Login with incorrect password did not error")
  106. }
  107. }
  108. func TestClient_SuccessfulLogin_UserRequiringPreAuth(t *testing.T) {
  109. b, err := hex.DecodeString(testdata.TESTUSER2_KEYTAB)
  110. kt, _ := keytab.Parse(b)
  111. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  112. addr := os.Getenv("TEST_KDC_ADDR")
  113. if addr == "" {
  114. addr = testdata.TEST_KDC_ADDR
  115. }
  116. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  117. cl := NewClientWithKeytab("testuser2", "TEST.GOKRB5", kt)
  118. cl.WithConfig(c)
  119. err = cl.Login()
  120. if err != nil {
  121. t.Fatalf("Error on login: %v\n", err)
  122. }
  123. }
  124. func TestClient_SuccessfulLogin_UserRequiringPreAuth_TCPOnly(t *testing.T) {
  125. b, err := hex.DecodeString(testdata.TESTUSER2_KEYTAB)
  126. kt, _ := keytab.Parse(b)
  127. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  128. addr := os.Getenv("TEST_KDC_ADDR")
  129. if addr == "" {
  130. addr = testdata.TEST_KDC_ADDR
  131. }
  132. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  133. c.LibDefaults.UDPPreferenceLimit = 1
  134. cl := NewClientWithKeytab("testuser2", "TEST.GOKRB5", kt)
  135. cl.WithConfig(c)
  136. err = cl.Login()
  137. if err != nil {
  138. t.Fatalf("Error on login: %v\n", err)
  139. }
  140. }
  141. func TestClient_NetworkTimeout(t *testing.T) {
  142. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  143. kt, _ := keytab.Parse(b)
  144. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  145. c.Realms[0].KDC = []string{testdata.TEST_KDC_BADADDR + ":88"}
  146. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  147. cl.WithConfig(c)
  148. err = cl.Login()
  149. if err == nil {
  150. t.Fatal("Login with incorrect KDC address did not error")
  151. }
  152. }
  153. func TestClient_GetServiceTicket(t *testing.T) {
  154. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  155. kt, _ := keytab.Parse(b)
  156. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  157. addr := os.Getenv("TEST_KDC_ADDR")
  158. if addr == "" {
  159. addr = testdata.TEST_KDC_ADDR
  160. }
  161. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  162. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  163. cl.WithConfig(c)
  164. err = cl.Login()
  165. if err != nil {
  166. t.Fatalf("Error on login: %v\n", err)
  167. }
  168. spn := "HTTP/host.test.gokrb5"
  169. tkt, key, err := cl.GetServiceTicket(spn)
  170. if err != nil {
  171. t.Fatalf("Error getting service ticket: %v\n", err)
  172. }
  173. assert.Equal(t, spn, tkt.SName.GetPrincipalNameString())
  174. assert.Equal(t, 18, key.KeyType)
  175. //Check cache use - should get the same values back again
  176. tkt2, key2, err := cl.GetServiceTicket(spn)
  177. if err != nil {
  178. t.Fatalf("Error getting service ticket: %v\n", err)
  179. }
  180. assert.Equal(t, tkt.EncPart.Cipher, tkt2.EncPart.Cipher)
  181. assert.Equal(t, key.KeyValue, key2.KeyValue)
  182. }
  183. func TestClient_GetServiceTicket_OlderKDC(t *testing.T) {
  184. b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  185. kt, _ := keytab.Parse(b)
  186. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  187. addr := os.Getenv("TEST_KDC_ADDR")
  188. if addr == "" {
  189. addr = testdata.TEST_KDC_ADDR
  190. }
  191. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC_OLD}
  192. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  193. cl.WithConfig(c)
  194. err = cl.Login()
  195. if err != nil {
  196. t.Fatalf("Error on login: %v\n", err)
  197. }
  198. spn := "HTTP/host.test.gokrb5"
  199. tkt, key, err := cl.GetServiceTicket(spn)
  200. if err != nil {
  201. t.Fatalf("Error getting service ticket: %v\n", err)
  202. }
  203. assert.Equal(t, spn, tkt.SName.GetPrincipalNameString())
  204. assert.Equal(t, 18, key.KeyType)
  205. }
  206. func TestClient_SetSPNEGOHeader(t *testing.T) {
  207. b, _ := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  208. kt, _ := keytab.Parse(b)
  209. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  210. addr := os.Getenv("TEST_KDC_ADDR")
  211. if addr == "" {
  212. addr = testdata.TEST_KDC_ADDR
  213. }
  214. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  215. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  216. cl.WithConfig(c)
  217. err := cl.Login()
  218. if err != nil {
  219. t.Fatalf("Error on AS_REQ: %v\n", err)
  220. }
  221. url := os.Getenv("TEST_HTTP_URL")
  222. if url == "" {
  223. url = testdata.TEST_HTTP_URL
  224. }
  225. r, _ := http.NewRequest("GET", url, nil)
  226. httpResp, err := http.DefaultClient.Do(r)
  227. if err != nil {
  228. t.Fatalf("Request error: %v\n", err)
  229. }
  230. assert.Equal(t, http.StatusUnauthorized, httpResp.StatusCode, "Status code in response to client with no SPNEGO not as expected")
  231. err = cl.SetSPNEGOHeader(r, "HTTP/host.test.gokrb5")
  232. if err != nil {
  233. t.Fatalf("Error setting client SPNEGO header: %v", err)
  234. }
  235. httpResp, err = http.DefaultClient.Do(r)
  236. if err != nil {
  237. t.Fatalf("Request error: %v\n", err)
  238. }
  239. assert.Equal(t, http.StatusOK, httpResp.StatusCode, "Status code in response to client SPNEGO request not as expected")
  240. }
  241. func TestMultiThreadedClientUse(t *testing.T) {
  242. b, _ := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
  243. kt, _ := keytab.Parse(b)
  244. c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
  245. addr := os.Getenv("TEST_KDC_ADDR")
  246. if addr == "" {
  247. addr = testdata.TEST_KDC_ADDR
  248. }
  249. c.Realms[0].KDC = []string{addr + ":" + testdata.TEST_KDC}
  250. cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
  251. cl.WithConfig(c)
  252. for i := 0; i < 5; i++ {
  253. go login(t, &cl)
  254. }
  255. for i := 0; i < 5; i++ {
  256. go spnegoGet(t, &cl)
  257. }
  258. }
  259. func login(t *testing.T, cl *Client) {
  260. err := cl.Login()
  261. if err != nil {
  262. t.Fatalf("Error on AS_REQ: %v\n", err)
  263. }
  264. }
  265. func spnegoGet(t *testing.T, cl *Client) {
  266. url := os.Getenv("TEST_HTTP_URL")
  267. if url == "" {
  268. url = testdata.TEST_HTTP_URL
  269. }
  270. r, _ := http.NewRequest("GET", url, nil)
  271. httpResp, err := http.DefaultClient.Do(r)
  272. if err != nil {
  273. t.Fatalf("Request error: %v\n", err)
  274. }
  275. assert.Equal(t, http.StatusUnauthorized, httpResp.StatusCode, "Status code in response to client with no SPNEGO not as expected")
  276. err = cl.SetSPNEGOHeader(r, "HTTP/host.test.gokrb5")
  277. if err != nil {
  278. t.Fatalf("Error setting client SPNEGO header: %v", err)
  279. }
  280. httpResp, err = http.DefaultClient.Do(r)
  281. if err != nil {
  282. t.Fatalf("Request error: %v\n", err)
  283. }
  284. assert.Equal(t, http.StatusOK, httpResp.StatusCode, "Status code in response to client SPNEGO request not as expected")
  285. }
  286. func TestNewClientFromCCache(t *testing.T) {
  287. b, err := hex.DecodeString(testdata.CCACHE_TEST)
  288. if err != nil {
  289. t.Fatalf("Error decoding test data")
  290. }
  291. cc, err := credentials.ParseCCache(b)
  292. if err != nil {
  293. t.Fatal("Error getting test CCache")
  294. }
  295. cl, err := NewClientFromCCache(cc)
  296. if err != nil {
  297. t.Fatalf("Error creating client from CCache: %v", err)
  298. }
  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.WithConfig(c)
  306. if ok, err := cl.IsConfigured(); !ok {
  307. t.Fatalf("Client was not configured from CCache: %v", err)
  308. }
  309. }