@@ -22,6 +22,7 @@ import (
2222 "fmt"
2323 "net/http"
2424 "strings"
25+ "sync"
2526 "time"
2627
2728 "github.com/coreos/go-oidc/jose"
@@ -44,19 +45,53 @@ const (
4445 cfgRefreshToken = "refresh-token"
4546)
4647
48+ func init () {
49+ if err := restclient .RegisterAuthProviderPlugin ("oidc" , newOIDCAuthProvider ); err != nil {
50+ glog .Fatalf ("Failed to register oidc auth plugin: %v" , err )
51+ }
52+ }
53+
4754var (
4855 backoff = wait.Backoff {
4956 Duration : 1 * time .Second ,
5057 Factor : 2 ,
5158 Jitter : .1 ,
5259 Steps : 5 ,
5360 }
61+ cache = clientCache {cache : make (map [cacheKey ]* oidc.Client )}
5462)
5563
56- func init () {
57- if err := restclient .RegisterAuthProviderPlugin ("oidc" , newOIDCAuthProvider ); err != nil {
58- glog .Fatalf ("Failed to register oidc auth plugin: %v" , err )
59- }
64+ // Like TLS transports, keep a cache of OIDC clients indexed by issuer URL.
65+ type clientCache struct {
66+ mu sync.RWMutex
67+ cache map [cacheKey ]* oidc.Client
68+ }
69+
70+ type cacheKey struct {
71+ // Canonical issuer URL string of the provider.
72+ issuerURL string
73+
74+ // TODO(ericchiang): github.com/coreos/go-oidc/oidc can't create a client without
75+ // associating a client ID and secret. When we switch to the new go-oidc, we can
76+ // switch this key to only use the issuer URL.
77+ clientID string
78+ clientSecret string
79+
80+ // Don't use CA as cache key because we only add a cache entry if we can connect
81+ // to the issuer in the first place. A valid CA is a prerequisite.
82+ }
83+
84+ func (c * clientCache ) getClient (issuer , clientID , clientSecret string ) (* oidc.Client , bool ) {
85+ c .mu .RLock ()
86+ defer c .mu .RUnlock ()
87+ client , ok := c .cache [cacheKey {issuer , clientID , clientSecret }]
88+ return client , ok
89+ }
90+
91+ func (c * clientCache ) setClient (issuer , clientID , clientSecret string , client * oidc.Client ) {
92+ c .mu .Lock ()
93+ defer c .mu .Unlock ()
94+ c .cache [cacheKey {issuer , clientID , clientSecret }] = client
6095}
6196
6297func newOIDCAuthProvider (_ string , cfg map [string ]string , persister restclient.AuthProviderConfigPersister ) (restclient.AuthProvider , error ) {
@@ -75,57 +110,61 @@ func newOIDCAuthProvider(_ string, cfg map[string]string, persister restclient.A
75110 return nil , fmt .Errorf ("Must provide %s" , cfgClientSecret )
76111 }
77112
78- var certAuthData []byte
79- var err error
80- if cfg [cfgCertificateAuthorityData ] != "" {
81- certAuthData , err = base64 .StdEncoding .DecodeString (cfg [cfgCertificateAuthorityData ])
82- if err != nil {
83- return nil , err
113+ client , ok := cache .getClient (issuer , clientID , clientSecret )
114+ if ! ok {
115+ var certAuthData []byte
116+ var err error
117+ if cfg [cfgCertificateAuthorityData ] != "" {
118+ certAuthData , err = base64 .StdEncoding .DecodeString (cfg [cfgCertificateAuthorityData ])
119+ if err != nil {
120+ return nil , err
121+ }
84122 }
85- }
86-
87- clientConfig := restclient.Config {
88- TLSClientConfig : restclient.TLSClientConfig {
89- CAFile : cfg [cfgCertificateAuthority ],
90- CAData : certAuthData ,
91- },
92- }
93123
94- trans , err := restclient .TransportFor (& clientConfig )
95- if err != nil {
96- return nil , err
97- }
98- hc := & http.Client {Transport : trans }
124+ clientConfig := restclient.Config {
125+ TLSClientConfig : restclient.TLSClientConfig {
126+ CAFile : cfg [cfgCertificateAuthority ],
127+ CAData : certAuthData ,
128+ },
129+ }
99130
100- providerCfg , err := oidc .FetchProviderConfig (hc , issuer )
101- if err != nil {
102- return nil , fmt .Errorf ("error fetching provider config: %v" , err )
103- }
131+ trans , err := restclient .TransportFor (& clientConfig )
132+ if err != nil {
133+ return nil , err
134+ }
135+ hc := & http.Client {Transport : trans }
104136
105- scopes := strings .Split (cfg [cfgExtraScopes ], "," )
106- oidcCfg := oidc.ClientConfig {
107- HTTPClient : hc ,
108- Credentials : oidc.ClientCredentials {
109- ID : clientID ,
110- Secret : clientSecret ,
111- },
112- ProviderConfig : providerCfg ,
113- Scope : append (scopes , oidc .DefaultScope ... ),
114- }
137+ providerCfg , err := oidc .FetchProviderConfig (hc , issuer )
138+ if err != nil {
139+ return nil , fmt .Errorf ("error fetching provider config: %v" , err )
140+ }
115141
116- client , err := oidc .NewClient (oidcCfg )
117- if err != nil {
118- return nil , fmt .Errorf ("error creating OIDC Client: %v" , err )
142+ scopes := strings .Split (cfg [cfgExtraScopes ], "," )
143+ oidcCfg := oidc.ClientConfig {
144+ HTTPClient : hc ,
145+ Credentials : oidc.ClientCredentials {
146+ ID : clientID ,
147+ Secret : clientSecret ,
148+ },
149+ ProviderConfig : providerCfg ,
150+ Scope : append (scopes , oidc .DefaultScope ... ),
151+ }
152+ client , err = oidc .NewClient (oidcCfg )
153+ if err != nil {
154+ return nil , fmt .Errorf ("error creating OIDC Client: %v" , err )
155+ }
156+ cache .setClient (issuer , clientID , clientSecret , client )
119157 }
120158
121159 oClient := & oidcClient {client }
122160
123161 var initialIDToken jose.JWT
124162 if cfg [cfgIDToken ] != "" {
125- initialIDToken , err = jose .ParseJWT (cfg [cfgIDToken ])
163+ idToken , err : = jose .ParseJWT (cfg [cfgIDToken ])
126164 if err != nil {
127165 return nil , err
128166 }
167+ initialIDToken = idToken
129168 }
130169
131170 return & oidcAuthProvider {
0 commit comments