Skip to content

Commit 24e9024

Browse files
authored
Fix close in use certificate providers after double Close() method call on wrapper object (#7128)
1 parent 33faea8 commit 24e9024

File tree

1 file changed

+42
-2
lines changed

1 file changed

+42
-2
lines changed

credentials/tls/certprovider/store.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
package certprovider
2020

2121
import (
22+
"context"
2223
"fmt"
2324
"sync"
25+
"sync/atomic"
2426
)
2527

2628
// provStore is the global singleton certificate provider store.
@@ -53,6 +55,22 @@ type wrappedProvider struct {
5355
store *store
5456
}
5557

58+
// closedProvider always returns errProviderClosed error.
59+
type closedProvider struct{}
60+
61+
func (c closedProvider) KeyMaterial(ctx context.Context) (*KeyMaterial, error) {
62+
return nil, errProviderClosed
63+
}
64+
65+
func (c closedProvider) Close() {
66+
}
67+
68+
// singleCloseWrappedProvider wraps a provider instance with a reference count
69+
// to properly handle multiple calls to Close.
70+
type singleCloseWrappedProvider struct {
71+
provider atomic.Pointer[Provider]
72+
}
73+
5674
// store is a collection of provider instances, safe for concurrent access.
5775
type store struct {
5876
mu sync.Mutex
@@ -75,6 +93,28 @@ func (wp *wrappedProvider) Close() {
7593
}
7694
}
7795

96+
// Close overrides the Close method of the embedded provider to avoid release the
97+
// already released reference.
98+
func (w *singleCloseWrappedProvider) Close() {
99+
newProvider := Provider(closedProvider{})
100+
oldProvider := w.provider.Swap(&newProvider)
101+
(*oldProvider).Close()
102+
}
103+
104+
// KeyMaterial returns the key material sourced by the Provider.
105+
// Callers are expected to use the returned value as read-only.
106+
func (w *singleCloseWrappedProvider) KeyMaterial(ctx context.Context) (*KeyMaterial, error) {
107+
return (*w.provider.Load()).KeyMaterial(ctx)
108+
}
109+
110+
// newSingleCloseWrappedProvider create wrapper a provider instance with a reference count
111+
// to properly handle multiple calls to Close.
112+
func newSingleCloseWrappedProvider(provider Provider) *singleCloseWrappedProvider {
113+
w := &singleCloseWrappedProvider{}
114+
w.provider.Store(&provider)
115+
return w
116+
}
117+
78118
// BuildableConfig wraps parsed provider configuration and functionality to
79119
// instantiate provider instances.
80120
type BuildableConfig struct {
@@ -112,7 +152,7 @@ func (bc *BuildableConfig) Build(opts BuildOptions) (Provider, error) {
112152
}
113153
if wp, ok := provStore.providers[sk]; ok {
114154
wp.refCount++
115-
return wp, nil
155+
return newSingleCloseWrappedProvider(wp), nil
116156
}
117157

118158
provider := bc.starter(opts)
@@ -126,7 +166,7 @@ func (bc *BuildableConfig) Build(opts BuildOptions) (Provider, error) {
126166
store: provStore,
127167
}
128168
provStore.providers[sk] = wp
129-
return wp, nil
169+
return newSingleCloseWrappedProvider(wp), nil
130170
}
131171

132172
// String returns the provider name and config as a colon separated string.

0 commit comments

Comments
 (0)