1515package authn
1616
1717import (
18+ "context"
1819 "os"
1920 "path/filepath"
2021 "sync"
@@ -45,6 +46,11 @@ type Keychain interface {
4546 Resolve (Resource ) (Authenticator , error )
4647}
4748
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+
4854// defaultKeychain implements Keychain with the semantics of the standard Docker
4955// credential keychain.
5056type defaultKeychain struct {
@@ -62,8 +68,23 @@ const (
6268 DefaultAuthKey = "https://" + name .DefaultRegistry + "/v1/"
6369)
6470
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.
6682func (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 ) {
6788 dk .mu .Lock ()
6889 defer dk .mu .Unlock ()
6990
@@ -180,6 +201,10 @@ func NewKeychainFromHelper(h Helper) Keychain { return wrapper{h} }
180201type wrapper struct { h Helper }
181202
182203func (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 ) {
183208 u , p , err := w .h .Get (r .RegistryStr ())
184209 if err != nil {
185210 return Anonymous , nil
@@ -206,8 +231,12 @@ type refreshingKeychain struct {
206231}
207232
208233func (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 ) {
209238 last := time .Now ()
210- auth , err := r .keychain . Resolve ( target )
239+ auth , err := Resolve ( ctx , r .keychain , target )
211240 if err != nil || auth == Anonymous {
212241 return auth , err
213242 }
@@ -236,17 +265,21 @@ type refreshing struct {
236265}
237266
238267func (r * refreshing ) Authorization () (* AuthConfig , error ) {
268+ return r .AuthorizationContext (context .Background ())
269+ }
270+
271+ func (r * refreshing ) AuthorizationContext (ctx context.Context ) (* AuthConfig , error ) {
239272 r .Lock ()
240273 defer r .Unlock ()
241274 if r .cached == nil || r .expired () {
242275 r .last = r .now ()
243- auth , err := r .keychain . Resolve ( r .target )
276+ auth , err := Resolve ( ctx , r .keychain , r .target )
244277 if err != nil {
245278 return nil , err
246279 }
247280 r .cached = auth
248281 }
249- return r .cached . Authorization ( )
282+ return Authorization ( ctx , r .cached )
250283}
251284
252285func (r * refreshing ) now () time.Time {
0 commit comments