session.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package client
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. "gopkg.in/jcmturner/gokrb5.v4/iana/nametype"
  7. "gopkg.in/jcmturner/gokrb5.v4/krberror"
  8. "gopkg.in/jcmturner/gokrb5.v4/messages"
  9. "gopkg.in/jcmturner/gokrb5.v4/types"
  10. )
  11. // Sessions keyed on the realm name
  12. type sessions struct {
  13. Entries map[string]*session
  14. mux sync.RWMutex
  15. }
  16. // Client session struct.
  17. type session struct {
  18. Realm string
  19. AuthTime time.Time
  20. EndTime time.Time
  21. RenewTill time.Time
  22. TGT messages.Ticket
  23. SessionKey types.EncryptionKey
  24. SessionKeyExpiration time.Time
  25. }
  26. // AddSession adds a session for a realm with a TGT to the client's session cache.
  27. // A goroutine is started to automatically renew the TGT before expiry.
  28. func (cl *Client) AddSession(tkt messages.Ticket, dep messages.EncKDCRepPart) {
  29. cl.sessions.mux.Lock()
  30. defer cl.sessions.mux.Unlock()
  31. s := &session{
  32. Realm: tkt.SName.NameString[1],
  33. AuthTime: dep.AuthTime,
  34. EndTime: dep.EndTime,
  35. RenewTill: dep.RenewTill,
  36. TGT: tkt,
  37. SessionKey: dep.Key,
  38. SessionKeyExpiration: dep.KeyExpiration,
  39. }
  40. cl.sessions.Entries[tkt.SName.NameString[1]] = s
  41. cl.enableAutoSessionRenewal(s)
  42. }
  43. // EnableAutoSessionRenewal turns on the automatic renewal for the client's TGT session.
  44. func (cl *Client) enableAutoSessionRenewal(s *session) {
  45. // TODO look into using a context here
  46. go func(s *session) {
  47. for {
  48. //Wait until one minute before endtime
  49. w := (s.EndTime.Sub(time.Now().UTC()) * 5) / 6
  50. if w < 0 {
  51. return
  52. }
  53. time.Sleep(w)
  54. cl.updateSession(s)
  55. }
  56. }(s)
  57. }
  58. // RenewTGT renews the client's TGT session.
  59. func (cl *Client) renewTGT(s *session) error {
  60. spn := types.PrincipalName{
  61. NameType: nametype.KRB_NT_SRV_INST,
  62. NameString: []string{"krbtgt", s.Realm},
  63. }
  64. _, tgsRep, err := cl.TGSExchange(spn, s.TGT.Realm, s.TGT, s.SessionKey, true, 0)
  65. if err != nil {
  66. return krberror.Errorf(err, krberror.KRBMsgError, "Error renewing TGT")
  67. }
  68. s.AuthTime = tgsRep.DecryptedEncPart.AuthTime
  69. s.AuthTime = tgsRep.DecryptedEncPart.AuthTime
  70. s.EndTime = tgsRep.DecryptedEncPart.EndTime
  71. s.RenewTill = tgsRep.DecryptedEncPart.RenewTill
  72. s.TGT = tgsRep.Ticket
  73. s.SessionKey = tgsRep.DecryptedEncPart.Key
  74. s.SessionKeyExpiration = tgsRep.DecryptedEncPart.KeyExpiration
  75. return nil
  76. }
  77. func (cl *Client) updateSession(s *session) error {
  78. if time.Now().UTC().Before(s.RenewTill) {
  79. err := cl.renewTGT(s)
  80. if err != nil {
  81. return err
  82. }
  83. } else {
  84. err := cl.ASExchange(s.Realm, 0)
  85. if err != nil {
  86. return err
  87. }
  88. }
  89. return nil
  90. }
  91. func (cl *Client) getSessionFromRemoteRealm(realm string) (*session, error) {
  92. cl.sessions.mux.RLock()
  93. sess, ok := cl.sessions.Entries[cl.Credentials.Realm]
  94. cl.sessions.mux.RUnlock()
  95. if !ok {
  96. return nil, fmt.Errorf("client does not have a session for realm %s, login first", cl.Credentials.Realm)
  97. }
  98. spn := types.PrincipalName{
  99. NameType: nametype.KRB_NT_SRV_INST,
  100. NameString: []string{"krbtgt", realm},
  101. }
  102. _, tgsRep, err := cl.TGSExchange(spn, cl.Credentials.Realm, sess.TGT, sess.SessionKey, false, 0)
  103. if err != nil {
  104. return nil, err
  105. }
  106. cl.AddSession(tgsRep.Ticket, tgsRep.DecryptedEncPart)
  107. cl.sessions.mux.RLock()
  108. defer cl.sessions.mux.RUnlock()
  109. return cl.sessions.Entries[realm], nil
  110. }
  111. // GetSessionFromRealm returns the session for the realm provided.
  112. func (cl *Client) GetSessionFromRealm(realm string) (*session, error) {
  113. cl.sessions.mux.RLock()
  114. sess, ok := cl.sessions.Entries[realm]
  115. cl.sessions.mux.RUnlock()
  116. if !ok {
  117. // Try to request TGT from trusted remote Realm
  118. return cl.getSessionFromRemoteRealm(realm)
  119. }
  120. return sess, nil
  121. }
  122. // GetSessionFromPrincipalName returns the session for the realm of the principal provided.
  123. func (cl *Client) GetSessionFromPrincipalName(spn types.PrincipalName) (*session, error) {
  124. realm := cl.Config.ResolveRealm(spn.NameString[len(spn.NameString)-1])
  125. return cl.GetSessionFromRealm(realm)
  126. }