cache.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package client
  2. import (
  3. "gopkg.in/jcmturner/gokrb5.v6/messages"
  4. "gopkg.in/jcmturner/gokrb5.v6/types"
  5. "strings"
  6. "sync"
  7. "time"
  8. )
  9. // Cache for client tickets.
  10. type Cache struct {
  11. Entries map[string]CacheEntry
  12. mux sync.RWMutex
  13. }
  14. // CacheEntry holds details for a client cache entry.
  15. type CacheEntry struct {
  16. Ticket messages.Ticket
  17. AuthTime time.Time
  18. StartTime time.Time
  19. EndTime time.Time
  20. RenewTill time.Time
  21. SessionKey types.EncryptionKey
  22. }
  23. // NewCache creates a new client ticket cache instance.
  24. func NewCache() *Cache {
  25. return &Cache{
  26. Entries: map[string]CacheEntry{},
  27. }
  28. }
  29. // GetEntry returns a cache entry that matches the SPN.
  30. func (c *Cache) getEntry(spn string) (CacheEntry, bool) {
  31. c.mux.RLock()
  32. defer c.mux.RUnlock()
  33. e, ok := (*c).Entries[spn]
  34. return e, ok
  35. }
  36. // AddEntry adds a ticket to the cache.
  37. func (c *Cache) addEntry(tkt messages.Ticket, authTime, startTime, endTime, renewTill time.Time, sessionKey types.EncryptionKey) CacheEntry {
  38. spn := strings.Join(tkt.SName.NameString, "/")
  39. c.mux.Lock()
  40. defer c.mux.Unlock()
  41. (*c).Entries[spn] = CacheEntry{
  42. Ticket: tkt,
  43. AuthTime: authTime,
  44. StartTime: startTime,
  45. EndTime: endTime,
  46. RenewTill: renewTill,
  47. SessionKey: sessionKey,
  48. }
  49. return c.Entries[spn]
  50. }
  51. // Clear deletes all the cache entries
  52. func (c *Cache) clear() {
  53. c.mux.Lock()
  54. defer c.mux.Unlock()
  55. for k := range c.Entries {
  56. delete(c.Entries, k)
  57. }
  58. }
  59. // RemoveEntry removes the cache entry for the defined SPN.
  60. func (c *Cache) RemoveEntry(spn string) {
  61. c.mux.Lock()
  62. defer c.mux.Unlock()
  63. delete(c.Entries, spn)
  64. }
  65. // GetCachedTicket returns a ticket from the cache for the SPN.
  66. // Only a ticket that is currently valid will be returned.
  67. func (cl *Client) GetCachedTicket(spn string) (messages.Ticket, types.EncryptionKey, bool) {
  68. if e, ok := cl.cache.getEntry(spn); ok {
  69. //If within time window of ticket return it
  70. if time.Now().UTC().After(e.StartTime) && time.Now().UTC().Before(e.EndTime) {
  71. return e.Ticket, e.SessionKey, true
  72. } else if time.Now().UTC().Before(e.RenewTill) {
  73. e, err := cl.renewTicket(e)
  74. if err != nil {
  75. return e.Ticket, e.SessionKey, false
  76. }
  77. return e.Ticket, e.SessionKey, true
  78. }
  79. }
  80. var tkt messages.Ticket
  81. var key types.EncryptionKey
  82. return tkt, key, false
  83. }
  84. // renewTicket renews a cache entry ticket.
  85. // To renew from outside the client package use GetCachedTicket
  86. func (cl *Client) renewTicket(e CacheEntry) (CacheEntry, error) {
  87. spn := e.Ticket.SName
  88. _, tgsRep, err := cl.TGSExchange(spn, e.Ticket.Realm, e.Ticket, e.SessionKey, true, 0)
  89. if err != nil {
  90. return e, err
  91. }
  92. e = cl.cache.addEntry(
  93. tgsRep.Ticket,
  94. tgsRep.DecryptedEncPart.AuthTime,
  95. tgsRep.DecryptedEncPart.StartTime,
  96. tgsRep.DecryptedEncPart.EndTime,
  97. tgsRep.DecryptedEncPart.RenewTill,
  98. tgsRep.DecryptedEncPart.Key,
  99. )
  100. return e, nil
  101. }