forked from vmware-archive/atc
-
Notifications
You must be signed in to change notification settings - Fork 1
/
reauther.go
125 lines (99 loc) · 2.51 KB
/
reauther.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package vault
import (
"sync"
"time"
"github.com/cenkalti/backoff"
)
// An Auther is anything which needs to be logged in and then have
// that login renewed on a regulary basis.
type Auther interface {
Login() (time.Duration, error)
Renew() (time.Duration, error)
}
// The ReAuther runs the authorization loop (login, renew) and retries
// using a bounded exponential backoff strategy. If maxTTL is set, a
// new login will be done _regardless_ of the available leaseDuration.
type ReAuther struct {
auther Auther
base time.Duration
max time.Duration
maxTTL time.Duration
loggedIn chan struct{}
loggedInOnce *sync.Once
}
// NewReAuther with a retry time and a max retry time.
func NewReAuther(auther Auther, maxTTL, retry, max time.Duration) *ReAuther {
ra := &ReAuther{
auther: auther,
base: retry,
max: max,
maxTTL: maxTTL,
loggedIn: make(chan struct{}, 1),
loggedInOnce: &sync.Once{},
}
go ra.authLoop()
return ra
}
// LoggedIn will receive a signal after every login. Multiple logins
// may result in a single signal as this channel is not blocked.
func (ra *ReAuther) LoggedIn() <-chan struct{} {
return ra.loggedIn
}
// we can't renew a secret that has exceeded it's maxTTL or it's lease
func (ra *ReAuther) renewable(leaseEnd, tokenEOL time.Time) bool {
now := time.Now()
if ra.maxTTL != 0 && now.After(tokenEOL) {
// token has exceeded the configured max TTL
return false
}
if now.After(leaseEnd) {
// token has exceeded its lease
return false
}
return true
}
// sleep until the tokenEOl or half the lease duration
func (ra *ReAuther) sleep(leaseEnd, tokenEOL time.Time) {
if ra.maxTTL != 0 && leaseEnd.After(tokenEOL) {
time.Sleep(tokenEOL.Sub(time.Now()))
} else {
time.Sleep(leaseEnd.Sub(time.Now()) / 2)
}
}
func (ra *ReAuther) authLoop() {
var tokenEOL, leaseEnd time.Time
for {
exp := backoff.NewExponentialBackOff()
exp.MaxElapsedTime = ra.max
exp.InitialInterval = ra.base
for {
lease, err := ra.auther.Login()
if err != nil {
time.Sleep(exp.NextBackOff())
continue
}
exp.Reset()
ra.loggedInOnce.Do(func() {
close(ra.loggedIn)
})
now := time.Now()
tokenEOL = now.Add(ra.maxTTL)
leaseEnd = now.Add(lease)
ra.sleep(leaseEnd, tokenEOL)
break
}
for {
if !ra.renewable(leaseEnd, tokenEOL) {
break
}
lease, err := ra.auther.Renew()
if err != nil {
time.Sleep(exp.NextBackOff())
continue
}
exp.Reset()
leaseEnd = time.Now().Add(lease)
ra.sleep(leaseEnd, tokenEOL)
}
}
}