package service
import (
"github.com/jcmturner/gokrb5/v8/types"
"sync"
"time"
)
type Cache struct {
entries map [string ]clientEntries
mux sync .RWMutex
}
type clientEntries struct {
replayMap map [time .Time ]replayCacheEntry
seqNumber int64
subKey types .EncryptionKey
}
type replayCacheEntry struct {
presentedTime time .Time
sName types .PrincipalName
cTime time .Time
}
func (c *Cache ) getClientEntries (cname types .PrincipalName ) (clientEntries , bool ) {
c .mux .RLock ()
defer c .mux .RUnlock ()
ce , ok := c .entries [cname .PrincipalNameString ()]
return ce , ok
}
func (c *Cache ) getClientEntry (cname types .PrincipalName , t time .Time ) (replayCacheEntry , bool ) {
if ce , ok := c .getClientEntries (cname ); ok {
c .mux .RLock ()
defer c .mux .RUnlock ()
if e , ok := ce .replayMap [t ]; ok {
return e , true
}
}
return replayCacheEntry {}, false
}
var replayCache Cache
var once sync .Once
func GetReplayCache (d time .Duration ) *Cache {
once .Do (func () {
replayCache = Cache {
entries : make (map [string ]clientEntries ),
}
go func () {
for {
time .Sleep (d )
replayCache .ClearOldEntries (d )
}
}()
})
return &replayCache
}
func (c *Cache ) AddEntry (sname types .PrincipalName , a types .Authenticator ) {
ct := a .CTime .Add (time .Duration (a .Cusec ) * time .Microsecond )
if ce , ok := c .getClientEntries (a .CName ); ok {
c .mux .Lock ()
defer c .mux .Unlock ()
ce .replayMap [ct ] = replayCacheEntry {
presentedTime : time .Now ().UTC (),
sName : sname ,
cTime : ct ,
}
ce .seqNumber = a .SeqNumber
ce .subKey = a .SubKey
} else {
c .mux .Lock ()
defer c .mux .Unlock ()
c .entries [a .CName .PrincipalNameString ()] = clientEntries {
replayMap : map [time .Time ]replayCacheEntry {
ct : {
presentedTime : time .Now ().UTC (),
sName : sname ,
cTime : ct ,
},
},
seqNumber : a .SeqNumber ,
subKey : a .SubKey ,
}
}
}
func (c *Cache ) ClearOldEntries (d time .Duration ) {
c .mux .Lock ()
defer c .mux .Unlock ()
for ke , ce := range c .entries {
for k , e := range ce .replayMap {
if time .Now ().UTC ().Sub (e .presentedTime ) > d {
delete (ce .replayMap , k )
}
}
if len (ce .replayMap ) == 0 {
delete (c .entries , ke )
}
}
}
func (c *Cache ) IsReplay (sname types .PrincipalName , a types .Authenticator ) bool {
ct := a .CTime .Add (time .Duration (a .Cusec ) * time .Microsecond )
if e , ok := c .getClientEntry (a .CName , ct ); ok {
if e .sName .Equal (sname ) {
return true
}
}
c .AddEntry (sname , a )
return false
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .