client_integration_test.go 20 KB

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