15
15
package authn
16
16
17
17
import (
18
+ "context"
18
19
"os"
19
20
"path/filepath"
20
21
"sync"
@@ -45,6 +46,11 @@ type Keychain interface {
45
46
Resolve (Resource ) (Authenticator , error )
46
47
}
47
48
49
+ // ContextKeychain is like Keychain, but allows for context to be passed in.
50
+ type ContextKeychain interface {
51
+ ResolveContext (context.Context , Resource ) (Authenticator , error )
52
+ }
53
+
48
54
// defaultKeychain implements Keychain with the semantics of the standard Docker
49
55
// credential keychain.
50
56
type defaultKeychain struct {
@@ -62,8 +68,23 @@ const (
62
68
DefaultAuthKey = "https://" + name .DefaultRegistry + "/v1/"
63
69
)
64
70
65
- // Resolve implements Keychain.
71
+ // Resolve calls ResolveContext with ctx if the given [Keychain] implements [ContextKeychain],
72
+ // otherwise it calls Resolve with the given [Resource].
73
+ func Resolve (ctx context.Context , keychain Keychain , target Resource ) (Authenticator , error ) {
74
+ if rctx , ok := keychain .(ContextKeychain ); ok {
75
+ return rctx .ResolveContext (ctx , target )
76
+ }
77
+
78
+ return keychain .Resolve (target )
79
+ }
80
+
81
+ // ResolveContext implements ContextKeychain.
66
82
func (dk * defaultKeychain ) Resolve (target Resource ) (Authenticator , error ) {
83
+ return dk .ResolveContext (context .Background (), target )
84
+ }
85
+
86
+ // Resolve implements Keychain.
87
+ func (dk * defaultKeychain ) ResolveContext (ctx context.Context , target Resource ) (Authenticator , error ) {
67
88
dk .mu .Lock ()
68
89
defer dk .mu .Unlock ()
69
90
@@ -180,6 +201,10 @@ func NewKeychainFromHelper(h Helper) Keychain { return wrapper{h} }
180
201
type wrapper struct { h Helper }
181
202
182
203
func (w wrapper ) Resolve (r Resource ) (Authenticator , error ) {
204
+ return w .ResolveContext (context .Background (), r )
205
+ }
206
+
207
+ func (w wrapper ) ResolveContext (ctx context.Context , r Resource ) (Authenticator , error ) {
183
208
u , p , err := w .h .Get (r .RegistryStr ())
184
209
if err != nil {
185
210
return Anonymous , nil
@@ -206,8 +231,12 @@ type refreshingKeychain struct {
206
231
}
207
232
208
233
func (r * refreshingKeychain ) Resolve (target Resource ) (Authenticator , error ) {
234
+ return r .ResolveContext (context .Background (), target )
235
+ }
236
+
237
+ func (r * refreshingKeychain ) ResolveContext (ctx context.Context , target Resource ) (Authenticator , error ) {
209
238
last := time .Now ()
210
- auth , err := r .keychain . Resolve ( target )
239
+ auth , err := Resolve ( ctx , r .keychain , target )
211
240
if err != nil || auth == Anonymous {
212
241
return auth , err
213
242
}
@@ -236,17 +265,21 @@ type refreshing struct {
236
265
}
237
266
238
267
func (r * refreshing ) Authorization () (* AuthConfig , error ) {
268
+ return r .AuthorizationContext (context .Background ())
269
+ }
270
+
271
+ func (r * refreshing ) AuthorizationContext (ctx context.Context ) (* AuthConfig , error ) {
239
272
r .Lock ()
240
273
defer r .Unlock ()
241
274
if r .cached == nil || r .expired () {
242
275
r .last = r .now ()
243
- auth , err := r .keychain . Resolve ( r .target )
276
+ auth , err := Resolve ( ctx , r .keychain , r .target )
244
277
if err != nil {
245
278
return nil , err
246
279
}
247
280
r .cached = auth
248
281
}
249
- return r .cached . Authorization ( )
282
+ return Authorization ( ctx , r .cached )
250
283
}
251
284
252
285
func (r * refreshing ) now () time.Time {
0 commit comments