Skip to content

Commit b0bfaf3

Browse files
Merge pull request #781 from jacobsee/OCPBUGS-59909/dont-cache-non-decodable-oidc-forever
OCPBUGS-59909: Don't cache server errors when checking for password grant support
2 parents cc54807 + d0e360b commit b0bfaf3

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

pkg/controllers/configobservation/oauth/idp_conversions.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,10 @@ func checkOIDCPasswordGrantFlow(
425425
}
426426
defer resp.Body.Close()
427427

428+
if resp.StatusCode >= 500 && resp.StatusCode <= 599 {
429+
return false, fmt.Errorf("OIDC token endpoint returned server error %d (%s)", resp.StatusCode, tokenURL)
430+
}
431+
428432
respJSON := json.NewDecoder(resp.Body)
429433
respMap := map[string]interface{}{}
430434
if err = respJSON.Decode(&respMap); err != nil {

pkg/controllers/configobservation/oauth/idp_conversions_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,99 @@ func injectServerURLToOIDCExpected(provider *osinv1.OpenIDIdentityProvider, serv
276276
provider.URLs.Token = strings.Replace(provider.URLs.Token, "${OIDC_URL}", serverURL, 1)
277277
provider.URLs.UserInfo = strings.Replace(provider.URLs.UserInfo, "${OIDC_URL}", serverURL, 1)
278278
}
279+
280+
func TestCheckOIDCPasswordGrantFlowCaching(t *testing.T) {
281+
var responseContent string
282+
shouldError := false
283+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
284+
if shouldError {
285+
http.Error(w, "internal server error", http.StatusInternalServerError)
286+
return
287+
}
288+
w.Write([]byte(responseContent))
289+
}))
290+
defer server.Close()
291+
292+
secret := &corev1.Secret{
293+
ObjectMeta: v1.ObjectMeta{
294+
Name: "test-secret",
295+
Namespace: "openshift-config",
296+
ResourceVersion: "test-version-1",
297+
},
298+
Data: map[string][]byte{
299+
"clientSecret": []byte("test-secret"),
300+
},
301+
}
302+
303+
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
304+
require.NoError(t, indexer.Add(secret))
305+
cmLister := corelistersv1.NewConfigMapLister(indexer)
306+
secretLister := corelistersv1.NewSecretLister(indexer)
307+
308+
t.Run("5xx responses are not cached", func(t *testing.T) {
309+
shouldError = true
310+
result, err := checkOIDCPasswordGrantFlow(
311+
cmLister,
312+
secretLister,
313+
server.URL+"/token",
314+
"test-client",
315+
configv1.ConfigMapNameReference{Name: ""},
316+
configv1.SecretNameReference{Name: "test-secret"},
317+
)
318+
319+
require.Error(t, err)
320+
require.False(t, result)
321+
require.NotContains(t, oidcPasswordChecks, "test-version-1")
322+
})
323+
324+
t.Run("valid JSON with invalid_grant is cached", func(t *testing.T) {
325+
responseContent = `{"error": "invalid_grant"}`
326+
shouldError = false
327+
result, err := checkOIDCPasswordGrantFlow(
328+
cmLister,
329+
secretLister,
330+
server.URL+"/token",
331+
"test-client",
332+
configv1.ConfigMapNameReference{Name: ""},
333+
configv1.SecretNameReference{Name: "test-secret"},
334+
)
335+
336+
require.NoError(t, err)
337+
require.True(t, result)
338+
require.Contains(t, oidcPasswordChecks, "test-version-1")
339+
require.True(t, oidcPasswordChecks["test-version-1"])
340+
})
341+
342+
t.Run("5xx then valid JSON results in cache only after success", func(t *testing.T) {
343+
oidcPasswordChecks = map[string]bool{}
344+
345+
shouldError = true
346+
res1, err := checkOIDCPasswordGrantFlow(
347+
cmLister,
348+
secretLister,
349+
server.URL+"/token",
350+
"test-client",
351+
configv1.ConfigMapNameReference{Name: ""},
352+
configv1.SecretNameReference{Name: "test-secret"},
353+
)
354+
require.Error(t, err)
355+
require.False(t, res1)
356+
require.NotContains(t, oidcPasswordChecks, "test-version-1")
357+
358+
// now server returns valid JSON allowing password grant check to be cached
359+
responseContent = `{"error": "invalid_grant"}`
360+
shouldError = false
361+
res2, err := checkOIDCPasswordGrantFlow(
362+
cmLister,
363+
secretLister,
364+
server.URL+"/token",
365+
"test-client",
366+
configv1.ConfigMapNameReference{Name: ""},
367+
configv1.SecretNameReference{Name: "test-secret"},
368+
)
369+
require.NoError(t, err)
370+
require.True(t, res2)
371+
require.Contains(t, oidcPasswordChecks, "test-version-1")
372+
require.True(t, oidcPasswordChecks["test-version-1"])
373+
})
374+
}

0 commit comments

Comments
 (0)