-
Notifications
You must be signed in to change notification settings - Fork 247
/
session.go
108 lines (99 loc) · 2.88 KB
/
session.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package client
import (
"fmt"
"gopkg.in/jcmturner/gokrb5.v1/iana/nametype"
"gopkg.in/jcmturner/gokrb5.v1/krberror"
"gopkg.in/jcmturner/gokrb5.v1/messages"
"gopkg.in/jcmturner/gokrb5.v1/types"
"time"
)
// Sessions keyed on the realm name
type sessions map[string]*session
// Client session struct.
type session struct {
Realm string
AuthTime time.Time
EndTime time.Time
RenewTill time.Time
TGT messages.Ticket
SessionKey types.EncryptionKey
SessionKeyExpiration time.Time
}
//
func (cl *Client) AddSession(tkt messages.Ticket, dep messages.EncKDCRepPart) {
s := &session{
Realm: tkt.SName.NameString[1],
AuthTime: dep.AuthTime,
EndTime: dep.EndTime,
RenewTill: dep.RenewTill,
TGT: tkt,
SessionKey: dep.Key,
SessionKeyExpiration: dep.KeyExpiration,
}
cl.sessions[tkt.SName.NameString[1]] = s
cl.EnableAutoSessionRenewal(s)
}
// EnableAutoSessionRenewal turns on the automatic renewal for the client's TGT session.
func (cl *Client) EnableAutoSessionRenewal(s *session) {
// TODO look into using a context here
go func(s *session) {
for {
//Wait until one minute before endtime
w := (s.EndTime.Sub(time.Now().UTC()) * 5) / 6
if w < 0 {
return
}
time.Sleep(w)
cl.updateSession(s)
}
}(s)
}
// RenewTGT renews the client's TGT session.
func (cl *Client) RenewTGT(s *session) error {
spn := types.PrincipalName{
NameType: nametype.KRB_NT_SRV_INST,
NameString: []string{"krbtgt", s.Realm},
}
_, tgsRep, err := cl.TGSExchange(spn, s.TGT.Realm, s.TGT, s.SessionKey, true, 0)
if err != nil {
return krberror.Errorf(err, krberror.KRBMsgError, "Error renewing TGT")
}
s.AuthTime = tgsRep.DecryptedEncPart.AuthTime
s.AuthTime = tgsRep.DecryptedEncPart.AuthTime
s.EndTime = tgsRep.DecryptedEncPart.EndTime
s.RenewTill = tgsRep.DecryptedEncPart.RenewTill
s.TGT = tgsRep.Ticket
s.SessionKey = tgsRep.DecryptedEncPart.Key
s.SessionKeyExpiration = tgsRep.DecryptedEncPart.KeyExpiration
return nil
}
func (cl *Client) updateSession(s *session) error {
if time.Now().UTC().Before(s.RenewTill) {
err := cl.RenewTGT(s)
if err != nil {
return err
}
} else {
err := cl.ASExchange(s.Realm)
if err != nil {
return err
}
}
return nil
}
func (cl *Client) GetSessionFromRealm(realm string) (sess *session, err error) {
var ok bool
sess, ok = cl.sessions[realm]
if !ok {
sess, ok = cl.sessions[cl.Config.LibDefaults.DefaultRealm]
if !ok {
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)
return
}
}
return
}
func (cl *Client) GetSessionFromPrincipalName(spn types.PrincipalName) (*session, error) {
realm := cl.Config.ResolveRealm(spn.NameString[1])
return cl.GetSessionFromRealm(realm)
}