Skip to content

Commit 6c8997c

Browse files
committed
providers: don't cache login and redeem URLs
The code which was caching login and redeem URLs is actually working in parallel which may cause nil dereferences as the cache is being wiped out. Don't cache these urls at all.
1 parent d98a037 commit 6c8997c

File tree

7 files changed

+46
-76
lines changed

7 files changed

+46
-76
lines changed

oauthproxy.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -319,9 +319,9 @@ func (p *OAuthProxy) redeemCode(host, code string) (s *providers.SessionState, e
319319
}
320320
redirectURI := p.GetRedirectURI(host)
321321

322-
redeemURL := p.provider.GetRedeemURL()
323-
if redeemURL == nil {
324-
return s, fmt.Errorf("unable to discover the redeeem endpoint")
322+
redeemURL, err := p.provider.GetRedeemURL()
323+
if err != nil {
324+
return s, err
325325
}
326326
s, err = p.provider.Redeem(redeemURL, redirectURI, code)
327327
if err != nil {
@@ -612,13 +612,10 @@ func (p *OAuthProxy) OAuthStart(rw http.ResponseWriter, req *http.Request) {
612612
return
613613
}
614614

615-
// clear cached endpoints, get fresh ones in case /.well-known/oauth-authorization-server changed its values
616-
p.provider.ClearEndpointsCache()
617-
618615
redirectURI := p.GetRedirectURI(req.Host)
619-
loginURL := p.provider.GetLoginURL()
620-
if loginURL == nil {
621-
p.ErrorPage(rw, 500, "Internal Error", fmt.Sprintf("could not get login endpoint"))
616+
loginURL, err := p.provider.GetLoginURL()
617+
if err != nil {
618+
p.ErrorPage(rw, 500, "Internal Error", err.Error())
622619
return
623620
}
624621
http.Redirect(rw, req, p.provider.GetLoginRedirectURL(*loginURL, redirectURI, fmt.Sprintf("%v:%v", nonce, redirect)), 302)

oauthproxy_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,12 @@ func NewTestProvider(provider_url *url.URL, email_address string) *TestProvider
185185
return &TestProvider{
186186
ProviderData: &providers.ProviderData{
187187
ProviderName: "Test Provider",
188-
LoginURL: &url.URL{
188+
ConfigLoginURL: &url.URL{
189189
Scheme: "http",
190190
Host: provider_url.Host,
191191
Path: "/oauth/authorize",
192192
},
193-
RedeemURL: &url.URL{
193+
ConfigRedeemURL: &url.URL{
194194
Scheme: "http",
195195
Host: provider_url.Host,
196196
Path: "/oauth/token",

options.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,8 @@ func (o *Options) validateProvider(provider providers.Provider) []string {
336336
p.ClientID = data.ClientID
337337
p.ClientSecret = data.ClientSecret
338338
p.ApprovalPrompt = data.ApprovalPrompt
339-
p.LoginURL = data.LoginURL
340-
p.RedeemURL = data.RedeemURL
339+
p.ConfigLoginURL = data.ConfigLoginURL
340+
p.ConfigRedeemURL = data.ConfigRedeemURL
341341
p.ProfileURL = data.ProfileURL
342342
p.ValidateURL = data.ValidateURL
343343
}

providers/openshift/provider.go

Lines changed: 26 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,6 @@ func (p *OpenShiftProvider) LoadDefaults(serviceAccount string, caPaths []string
108108
}
109109
}
110110

111-
// attempt to discover endpoints
112-
if err := discoverOpenShiftOAuth(defaults, p.Client); err != nil {
113-
log.Printf("Unable to discover default cluster OAuth info: %v", err)
114-
return defaults, nil
115-
}
116111
// provide default URLs
117112
defaults.ValidateURL = getKubeAPIURLWithPath("/apis/user.openshift.io/v1/users/~")
118113

@@ -510,67 +505,54 @@ func (p *OpenShiftProvider) Redeem(redeemURL *url.URL, redirectURL, code string)
510505
return
511506
}
512507

513-
func (p *OpenShiftProvider) GetLoginURL() *url.URL {
508+
func (p *OpenShiftProvider) GetLoginURL() (*url.URL, error) {
514509
if !emptyURL(p.ConfigLoginURL) {
515-
return p.ConfigLoginURL
510+
return p.ConfigLoginURL, nil
516511
}
517512

518-
if emptyURL(p.LoginURL) {
519-
// clear the endpoints so that we get all the newly discovered endpoints for all
520-
p.ClearEndpointsCache()
521-
discoverOpenShiftOAuth(p.ProviderData, p.Client)
522-
}
523-
return p.LoginURL
513+
loginURL, _, err := discoverOpenShiftOAuth(p.Client)
514+
return loginURL, err
524515
}
525516

526-
func (p *OpenShiftProvider) GetRedeemURL() *url.URL {
517+
func (p *OpenShiftProvider) GetRedeemURL() (*url.URL, error) {
527518
if !emptyURL(p.ConfigRedeemURL) {
528-
return p.ConfigRedeemURL
519+
return p.ConfigRedeemURL, nil
529520
}
530521

531-
if emptyURL(p.RedeemURL) {
532-
// clear the endpoints so that we get all the newly discovered endpoints
533-
p.ClearEndpointsCache()
534-
discoverOpenShiftOAuth(p.ProviderData, p.Client)
535-
}
536-
return p.RedeemURL
522+
_, redeemURL, err := discoverOpenShiftOAuth(p.Client)
523+
return redeemURL, err
537524
}
538525

539-
// discoverOpenshiftOAuth sets the LoginURL and RedeemURL of the supplied ProviderData if they are unset or empty
540-
func discoverOpenShiftOAuth(provider *providers.ProviderData, client *http.Client) error {
526+
// discoverOpenshiftOAuth returns the urls of the login and code redeem endpoitns
527+
// it receives from the /.well-known/oauth-authorization-server endpoint
528+
func discoverOpenShiftOAuth(client *http.Client) (*url.URL, *url.URL, error) {
541529
wellKnownAuthorization := getKubeAPIURLWithPath("/.well-known/oauth-authorization-server")
542530
log.Printf("Performing OAuth discovery against %s", wellKnownAuthorization)
543531
req, err := http.NewRequest("GET", wellKnownAuthorization.String(), nil)
544532
if err != nil {
545-
return err
533+
return nil, nil, err
546534
}
547535
json, err := request(client, req)
548536
if err != nil {
549-
return err
537+
return nil, nil, err
550538
}
551-
if emptyURL(provider.LoginURL) {
552-
if value, err := json.Get("authorization_endpoint").String(); err == nil && len(value) > 0 {
553-
if u, err := url.Parse(value); err == nil {
554-
provider.LoginURL = u
555-
} else {
556-
log.Printf("Unable to parse 'authorization_endpoint' from %s: %v", wellKnownAuthorization, err)
557-
}
558-
} else {
559-
log.Printf("No 'authorization_endpoint' provided by %s: %v", wellKnownAuthorization, err)
539+
540+
var loginURL, redeemURL *url.URL
541+
if value, err := json.Get("authorization_endpoint").String(); err == nil && len(value) > 0 {
542+
if loginURL, err = url.Parse(value); err != nil {
543+
return nil, nil, fmt.Errorf("Unable to parse 'authorization_endpoint' from %s: %v", wellKnownAuthorization, err)
560544
}
545+
} else {
546+
return nil, nil, fmt.Errorf("No 'authorization_endpoint' provided by %s: %v", wellKnownAuthorization, err)
561547
}
562-
if emptyURL(provider.RedeemURL) {
563-
if value, err := json.Get("token_endpoint").String(); err == nil && len(value) > 0 {
564-
if u, err := url.Parse(value); err == nil {
565-
provider.RedeemURL = u
566-
} else {
567-
log.Printf("Unable to parse 'token_endpoint' from %s: %v", wellKnownAuthorization, err)
568-
}
569-
} else {
570-
log.Printf("No 'token_endpoint' provided by %s: %v", wellKnownAuthorization, err)
548+
if value, err := json.Get("token_endpoint").String(); err == nil && len(value) > 0 {
549+
if redeemURL, err = url.Parse(value); err != nil {
550+
return nil, nil, fmt.Errorf("Unable to parse 'token_endpoint' from %s: %v", wellKnownAuthorization, err)
571551
}
552+
} else {
553+
return nil, nil, fmt.Errorf("No 'token_endpoint' provided by %s: %v", wellKnownAuthorization, err)
572554
}
573-
return nil
555+
return loginURL, redeemURL, nil
574556
}
575557

576558
// Copied to override http.Client so that CA can be set

providers/provider_data.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,8 @@ type ProviderData struct {
88
ProviderName string
99
ClientID string
1010
ClientSecret string
11-
// LoginURL, RedeemURL are cached in runtime, only set/unset
12-
// them in cache-related methods
13-
LoginURL *url.URL
14-
RedeemURL *url.URL
15-
// Config* attributes are attributes that are set in options and override
16-
// the cached attributes above
11+
// Config* attributes are set in the options, if set, these endpoints won't
12+
// be refetched
1713
ConfigLoginURL *url.URL
1814
ConfigRedeemURL *url.URL
1915
ValidateURL *url.URL

providers/provider_default.go

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,22 +127,18 @@ func (p *ProviderData) RefreshSessionIfNeeded(s *SessionState) (bool, error) {
127127
return false, nil
128128
}
129129

130-
func (p *ProviderData) GetLoginURL() *url.URL {
130+
func (p *ProviderData) GetLoginURL() (*url.URL, error) {
131131
if !(p.ConfigLoginURL == nil || p.ConfigLoginURL.String() == "") {
132-
return p.ConfigLoginURL
132+
return p.ConfigLoginURL, nil
133133
}
134134

135-
return p.LoginURL
135+
return nil, fmt.Errorf("no login endpoint was configured")
136136
}
137137

138-
func (p *ProviderData) GetRedeemURL() *url.URL {
138+
func (p *ProviderData) GetRedeemURL() (*url.URL, error) {
139139
if !(p.ConfigRedeemURL == nil || p.ConfigRedeemURL.String() == "") {
140-
return p.ConfigRedeemURL
140+
return p.ConfigRedeemURL, nil
141141
}
142-
return p.RedeemURL
143-
}
144142

145-
func (p *ProviderData) ClearEndpointsCache() {
146-
p.LoginURL = nil
147-
p.RedeemURL = nil
143+
return nil, fmt.Errorf("no redeem endpoint was configured")
148144
}

providers/providers.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ type Provider interface {
2121
SessionFromCookie(string, *cookie.Cipher) (*SessionState, error)
2222
CookieForSession(*SessionState, *cookie.Cipher) (string, error)
2323
ValidateRequest(*http.Request) (*SessionState, error)
24-
GetLoginURL() *url.URL
25-
GetRedeemURL() *url.URL
26-
ClearEndpointsCache()
24+
GetLoginURL() (*url.URL, error)
25+
GetRedeemURL() (*url.URL, error)
2726
}
2827

2928
// ErrPermissionDenied may be returned from Redeem() to indicate the user is not allowed to login.

0 commit comments

Comments
 (0)