session.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package client
  2. import (
  3. "fmt"
  4. "gopkg.in/jcmturner/gokrb5.v2/iana/nametype"
  5. "gopkg.in/jcmturner/gokrb5.v2/krberror"
  6. "gopkg.in/jcmturner/gokrb5.v2/messages"
  7. "gopkg.in/jcmturner/gokrb5.v2/types"
  8. "sync"
  9. "time"
  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. // GetSessionFromRealm returns the session for the realm provided.
  92. func (cl *Client) GetSessionFromRealm(realm string) (sess *session, err error) {
  93. var ok bool
  94. cl.sessions.mux.RLock()
  95. defer cl.sessions.mux.RUnlock()
  96. sess, ok = cl.sessions.Entries[realm]
  97. if !ok {
  98. sess, ok = cl.sessions.Entries[cl.Config.LibDefaults.DefaultRealm]
  99. if !ok {
  100. err = fmt.Errorf("client does not have a session for realm %s or for the default realm %s, login first", realm, cl.Config.LibDefaults.DefaultRealm)
  101. return
  102. }
  103. }
  104. return
  105. }
  106. // GetSessionFromPrincipalName returns the session for the realm of the principal provided.
  107. func (cl *Client) GetSessionFromPrincipalName(spn types.PrincipalName) (*session, error) {
  108. realm := cl.Config.ResolveRealm(spn.NameString[1])
  109. return cl.GetSessionFromRealm(realm)
  110. }