diff --git a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller.go b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller.go
index c4dd46884..951db2bfa 100644
--- a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller.go
+++ b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller.go
@@ -53,18 +53,21 @@ const (
typeJWKSFetchValid = "JWKSFetchValid"
typeAuthenticatorValid = "AuthenticatorValid"
- reasonSuccess = "Success"
- reasonNotReady = "NotReady"
- reasonUnableToValidate = "UnableToValidate"
- reasonInvalidIssuerURL = "InvalidIssuerURL"
- reasonInvalidIssuerURLScheme = "InvalidIssuerURLScheme"
- reasonInvalidProviderJWKSURL = "InvalidProviderJWKSURL"
- reasonInvalidProviderJWKSURLScheme = "InvalidProviderJWKSURLScheme"
- reasonInvalidTLSConfiguration = "InvalidTLSConfiguration"
- reasonInvalidDiscoveryProbe = "InvalidDiscoveryProbe"
- reasonInvalidAuthenticator = "InvalidAuthenticator"
- reasonInvalidTokenSigningFailure = "InvalidTokenSigningFailure"
- reasonInvalidCouldNotFetchJWKS = "InvalidCouldNotFetchJWKS"
+ reasonSuccess = "Success"
+ reasonNotReady = "NotReady"
+ reasonUnableToValidate = "UnableToValidate"
+ reasonInvalidIssuerURL = "InvalidIssuerURL"
+ reasonInvalidIssuerURLScheme = "InvalidIssuerURLScheme"
+ reasonInvalidIssuerURLFragment = "InvalidIssuerURLContainsFragment"
+ reasonInvalidIssuerURLQueryParams = "InvalidIssuerURLContainsQueryParams"
+ reasonInvalidIssuerURLContainsWellKnownEndpoint = "InvalidIssuerURLContainsWellKnownEndpoint"
+ reasonInvalidProviderJWKSURL = "InvalidProviderJWKSURL"
+ reasonInvalidProviderJWKSURLScheme = "InvalidProviderJWKSURLScheme"
+ reasonInvalidTLSConfiguration = "InvalidTLSConfiguration"
+ reasonInvalidDiscoveryProbe = "InvalidDiscoveryProbe"
+ reasonInvalidAuthenticator = "InvalidAuthenticator"
+ reasonInvalidTokenSigningFailure = "InvalidTokenSigningFailure"
+ reasonInvalidCouldNotFetchJWKS = "InvalidCouldNotFetchJWKS"
msgUnableToValidate = "unable to validate; see other conditions for details"
@@ -286,6 +289,39 @@ func (c *jwtCacheFillerController) validateIssuer(issuer string, conditions []*m
return nil, conditions, false
}
+ if strings.HasSuffix(issuerURL.Path, "/.well-known/openid-configuration") {
+ msg := fmt.Sprintf("spec.issuer %s cannot include path '/.well-known/openid-configuration'", issuer)
+ conditions = append(conditions, &metav1.Condition{
+ Type: typeIssuerURLValid,
+ Status: metav1.ConditionFalse,
+ Reason: reasonInvalidIssuerURLContainsWellKnownEndpoint,
+ Message: msg,
+ })
+ return nil, conditions, false
+ }
+
+ if len(issuerURL.Query()) != 0 {
+ msg := fmt.Sprintf("spec.issuer %s cannot include query params", issuer)
+ conditions = append(conditions, &metav1.Condition{
+ Type: typeIssuerURLValid,
+ Status: metav1.ConditionFalse,
+ Reason: reasonInvalidIssuerURLQueryParams,
+ Message: msg,
+ })
+ return nil, conditions, false
+ }
+
+ if issuerURL.Fragment != "" {
+ msg := fmt.Sprintf("spec.issuer %s cannot include fragment", issuer)
+ conditions = append(conditions, &metav1.Condition{
+ Type: typeIssuerURLValid,
+ Status: metav1.ConditionFalse,
+ Reason: reasonInvalidIssuerURLFragment,
+ Message: msg,
+ })
+ return nil, conditions, false
+ }
+
conditions = append(conditions, &metav1.Condition{
Type: typeIssuerURLValid,
Status: metav1.ConditionTrue,
@@ -305,11 +341,12 @@ func (c *jwtCacheFillerController) validateProviderDiscovery(ctx context.Context
})
return nil, nil, conditions, nil
}
+
provider, err := coreosoidc.NewProvider(ctx, issuer)
pJSON := &providerJSON{}
if err != nil {
errText := "could not perform oidc discovery on provider issuer"
- msg := fmt.Sprintf("%s: %s", errText, err.Error())
+ msg := fmt.Sprintf("%s: %s", errText, pinnipedcontroller.TruncateMostLongErr(err))
conditions = append(conditions, &metav1.Condition{
Type: typeDiscoveryValid,
Status: metav1.ConditionFalse,
@@ -317,7 +354,7 @@ func (c *jwtCacheFillerController) validateProviderDiscovery(ctx context.Context
Message: msg,
})
// resync err, may be machine or other types of non-config error
- return nil, nil, conditions, fmt.Errorf("%s: %w", errText, err)
+ return nil, nil, conditions, fmt.Errorf("%s: %s", errText, err)
}
msg := "discovery performed successfully"
conditions = append(conditions, &metav1.Condition{
diff --git a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go
index cb9f3d851..4b13a500b 100644
--- a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go
+++ b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go
@@ -87,6 +87,20 @@ func TestController(t *testing.T) {
_, err := fmt.Fprintf(w, `{"issuer": "%s", "jwks_uri": "%s"}`, goodOIDCIssuerServer.URL, goodOIDCIssuerServer.URL+"/jwks.json")
require.NoError(t, err)
}))
+ goodMux.Handle("/path/to/not/found", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusNotFound)
+ require.NoError(t, err)
+ }))
+ goodMux.Handle("/path/to/not/found/.well-known/openid-configuration", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusNotFound)
+ _, err := fmt.Fprintf(w, `
+
%s
+ %s
+ `, "404 not found page", "lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz should not reach end of string")
+ require.NoError(t, err)
+ }))
goodMux.Handle("/jwks.json", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ecJWK := jose.JSONWebKey{
Key: goodECSigningKey,
@@ -360,6 +374,39 @@ func TestController(t *testing.T) {
}
}
+ sadIssuerURLValidInvalidFragment := func(issuer string, time metav1.Time, observedGeneration int64) metav1.Condition {
+ return metav1.Condition{
+ Type: "IssuerURLValid",
+ Status: "False",
+ ObservedGeneration: observedGeneration,
+ LastTransitionTime: time,
+ Reason: "InvalidIssuerURLContainsFragment",
+ Message: fmt.Sprintf("spec.issuer %s cannot include fragment", issuer),
+ }
+ }
+
+ sadIssuerURLValidInvalidQueryParams := func(issuer string, time metav1.Time, observedGeneration int64) metav1.Condition {
+ return metav1.Condition{
+ Type: "IssuerURLValid",
+ Status: "False",
+ ObservedGeneration: observedGeneration,
+ LastTransitionTime: time,
+ Reason: "InvalidIssuerURLContainsQueryParams",
+ Message: fmt.Sprintf("spec.issuer %s cannot include query params", issuer),
+ }
+ }
+
+ sadIssuerURLValidInvalidWellKnownEndpoint := func(issuer string, time metav1.Time, observedGeneration int64) metav1.Condition {
+ return metav1.Condition{
+ Type: "IssuerURLValid",
+ Status: "False",
+ ObservedGeneration: observedGeneration,
+ LastTransitionTime: time,
+ Reason: "InvalidIssuerURLContainsWellKnownEndpoint",
+ Message: fmt.Sprintf("spec.issuer %s cannot include path '/.well-known/openid-configuration'", issuer),
+ }
+ }
+
happyAuthenticatorValid := func(time metav1.Time, observedGeneration int64) metav1.Condition {
return metav1.Condition{
Type: "AuthenticatorValid",
@@ -428,6 +475,17 @@ func TestController(t *testing.T) {
}
}
+ sadDiscoveryURLValidExcessiveLongError := func(issuer string, time metav1.Time, observedGeneration int64) metav1.Condition {
+ return metav1.Condition{
+ Type: "DiscoveryURLValid",
+ Status: "False",
+ ObservedGeneration: observedGeneration,
+ LastTransitionTime: time,
+ Reason: "InvalidDiscoveryProbe",
+ Message: "could not perform oidc discovery on provider issuer: 404 Not Found: \n\t\t \t404 not found page\n\t\t\tlots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 charact [truncated 534 chars]",
+ }
+ }
+
happyJWKSURLValid := func(time metav1.Time, observedGeneration int64) metav1.Condition {
return metav1.Condition{
Type: "JWKSURLValid",
@@ -1095,6 +1153,147 @@ func TestController(t *testing.T) {
updateStatusAction,
}
},
+ }, {
+ name: "validateIssuer: issuer cannot include fragment: loop will fail sync, will write failed and unknown conditions, but will not enqueue a resync due to user config error",
+ jwtAuthenticators: []runtime.Object{
+ &auth1alpha1.JWTAuthenticator{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-name",
+ },
+ Spec: auth1alpha1.JWTAuthenticatorSpec{
+ Issuer: "https://www.example.com/foo/bar/#do-not-include-fragment",
+ Audience: goodAudience,
+ TLS: conciergetestutil.TlsSpecFromTLSConfig(goodOIDCIssuerServer.TLS),
+ },
+ },
+ },
+ syncKey: controllerlib.Key{Name: "test-name"},
+ wantActions: func() []coretesting.Action {
+ updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &auth1alpha1.JWTAuthenticator{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-name",
+ },
+ Spec: auth1alpha1.JWTAuthenticatorSpec{
+ Issuer: "https://www.example.com/foo/bar/#do-not-include-fragment",
+ Audience: goodAudience,
+ TLS: conciergetestutil.TlsSpecFromTLSConfig(goodOIDCIssuerServer.TLS),
+ },
+ Status: auth1alpha1.JWTAuthenticatorStatus{
+ Conditions: conditionstestutil.Replace(
+ allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
+ []metav1.Condition{
+ sadReadyCondition(frozenMetav1Now, 0),
+ sadIssuerURLValidInvalidFragment("https://www.example.com/foo/bar/#do-not-include-fragment", frozenMetav1Now, 0),
+ unknownDiscoveryURLValid(frozenMetav1Now, 0),
+ unknownAuthenticatorValid(frozenMetav1Now, 0),
+ unknownJWKSURLValid(frozenMetav1Now, 0),
+ unknownJWKSFetch(frozenMetav1Now, 0),
+ },
+ ),
+ Phase: "Error",
+ },
+ })
+ updateStatusAction.Subresource = "status"
+ return []coretesting.Action{
+ coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
+ coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{}),
+ updateStatusAction,
+ }
+ },
+ }, {
+ name: "validateIssuer: issuer cannot include query params: loop will fail sync, will write failed and unknown conditions, but will not enqueue a resync due to user config error",
+ jwtAuthenticators: []runtime.Object{
+ &auth1alpha1.JWTAuthenticator{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-name",
+ },
+ Spec: auth1alpha1.JWTAuthenticatorSpec{
+ Issuer: "https://www.example.com/foo/bar/?query-params=not-allowed",
+ Audience: goodAudience,
+ TLS: conciergetestutil.TlsSpecFromTLSConfig(goodOIDCIssuerServer.TLS),
+ },
+ },
+ },
+ syncKey: controllerlib.Key{Name: "test-name"},
+ wantActions: func() []coretesting.Action {
+ updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &auth1alpha1.JWTAuthenticator{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-name",
+ },
+ Spec: auth1alpha1.JWTAuthenticatorSpec{
+ Issuer: "https://www.example.com/foo/bar/?query-params=not-allowed",
+ Audience: goodAudience,
+ TLS: conciergetestutil.TlsSpecFromTLSConfig(goodOIDCIssuerServer.TLS),
+ },
+ Status: auth1alpha1.JWTAuthenticatorStatus{
+ Conditions: conditionstestutil.Replace(
+ allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
+ []metav1.Condition{
+ sadReadyCondition(frozenMetav1Now, 0),
+ sadIssuerURLValidInvalidQueryParams("https://www.example.com/foo/bar/?query-params=not-allowed", frozenMetav1Now, 0),
+ unknownDiscoveryURLValid(frozenMetav1Now, 0),
+ unknownAuthenticatorValid(frozenMetav1Now, 0),
+ unknownJWKSURLValid(frozenMetav1Now, 0),
+ unknownJWKSFetch(frozenMetav1Now, 0),
+ },
+ ),
+ Phase: "Error",
+ },
+ })
+ updateStatusAction.Subresource = "status"
+ return []coretesting.Action{
+ coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
+ coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{}),
+ updateStatusAction,
+ }
+ },
+ }, {
+ name: "validateIssuer: issuer cannot include .well-known in path: loop will fail sync, will write failed and unknown conditions, but will not enqueue a resync due to user config error",
+ jwtAuthenticators: []runtime.Object{
+ &auth1alpha1.JWTAuthenticator{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-name",
+ },
+ Spec: auth1alpha1.JWTAuthenticatorSpec{
+ Issuer: "https://www.example.com/foo/bar/.well-known/openid-configuration",
+ Audience: goodAudience,
+ TLS: conciergetestutil.TlsSpecFromTLSConfig(goodOIDCIssuerServer.TLS),
+ },
+ },
+ },
+ syncKey: controllerlib.Key{Name: "test-name"},
+ wantActions: func() []coretesting.Action {
+ updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &auth1alpha1.JWTAuthenticator{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-name",
+ },
+ Spec: auth1alpha1.JWTAuthenticatorSpec{
+ Issuer: "https://www.example.com/foo/bar/.well-known/openid-configuration",
+ Audience: goodAudience,
+ TLS: conciergetestutil.TlsSpecFromTLSConfig(goodOIDCIssuerServer.TLS),
+ },
+ Status: auth1alpha1.JWTAuthenticatorStatus{
+ Conditions: conditionstestutil.Replace(
+ allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
+ []metav1.Condition{
+ sadReadyCondition(frozenMetav1Now, 0),
+ sadIssuerURLValidInvalidWellKnownEndpoint("https://www.example.com/foo/bar/.well-known/openid-configuration", frozenMetav1Now, 0),
+ unknownDiscoveryURLValid(frozenMetav1Now, 0),
+ unknownAuthenticatorValid(frozenMetav1Now, 0),
+ unknownJWKSURLValid(frozenMetav1Now, 0),
+ unknownJWKSFetch(frozenMetav1Now, 0),
+ },
+ ),
+ Phase: "Error",
+ },
+ })
+ updateStatusAction.Subresource = "status"
+ return []coretesting.Action{
+ coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
+ coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{}),
+ updateStatusAction,
+ }
+ },
}, {
name: "validateProviderDiscovery: could not perform oidc discovery on provider issuer: loop will fail sync, will write failed and unknown conditions, and will enqueue new sync",
jwtAuthenticators: []runtime.Object{
@@ -1136,6 +1335,56 @@ func TestController(t *testing.T) {
}
},
wantSyncLoopErr: testutil.WantExactErrorString(`could not perform oidc discovery on provider issuer: Get "` + goodIssuer + `/foo/bar/baz/shizzle/.well-known/openid-configuration": tls: failed to verify certificate: x509: certificate signed by unknown authority`),
+ }, {
+ name: "validateProviderDiscovery: excessively long errors truncated: loop will fail sync, will write failed and unknown conditions, and will enqueue new sync",
+ jwtAuthenticators: []runtime.Object{
+ &auth1alpha1.JWTAuthenticator{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-name",
+ },
+ Spec: auth1alpha1.JWTAuthenticatorSpec{
+ Issuer: goodIssuer + "/path/to/not/found",
+ Audience: goodAudience,
+ TLS: conciergetestutil.TlsSpecFromTLSConfig(goodOIDCIssuerServer.TLS),
+ },
+ },
+ },
+ syncKey: controllerlib.Key{Name: "test-name"},
+ wantActions: func() []coretesting.Action {
+ updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &auth1alpha1.JWTAuthenticator{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-name",
+ },
+ Spec: auth1alpha1.JWTAuthenticatorSpec{
+ Issuer: goodIssuer + "/path/to/not/found",
+ Audience: goodAudience,
+ TLS: conciergetestutil.TlsSpecFromTLSConfig(goodOIDCIssuerServer.TLS),
+ },
+ Status: auth1alpha1.JWTAuthenticatorStatus{
+ Conditions: conditionstestutil.Replace(
+ allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
+ []metav1.Condition{
+ happyIssuerURLValid(frozenMetav1Now, 0),
+ sadReadyCondition(frozenMetav1Now, 0),
+ sadDiscoveryURLValidExcessiveLongError(goodIssuer+"/path/to/not/found", frozenMetav1Now, 0),
+ unknownAuthenticatorValid(frozenMetav1Now, 0),
+ unknownJWKSURLValid(frozenMetav1Now, 0),
+ unknownJWKSFetch(frozenMetav1Now, 0),
+ happyTLSConfigurationValidCAParsed(frozenMetav1Now, 0),
+ },
+ ),
+ Phase: "Error",
+ },
+ })
+ updateStatusAction.Subresource = "status"
+ return []coretesting.Action{
+ coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
+ coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{}),
+ updateStatusAction,
+ }
+ },
+ // not currently truncating the logged err
+ wantSyncLoopErr: testutil.WantExactErrorString("could not perform oidc discovery on provider issuer: 404 Not Found: \n\t\t \t404 not found page\n\t\t\tlots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz lots of text that is at least 300 characters long 0123456789 abcdefghijklmnopqrstuvwxyz should not reach end of string\n\t\t"),
},
// cannot be tested currently the way the coreos lib works.
// the constructor requires an issuer in the payload and validates the issuer matches the actual issuer,
diff --git a/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher.go b/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher.go
index 9edf172f7..396df85dc 100644
--- a/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher.go
+++ b/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher.go
@@ -1,4 +1,4 @@
-// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
+// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package oidcupstreamwatcher implements a controller which watches OIDCIdentityProviders.
@@ -342,7 +342,7 @@ func (c *oidcWatcherController) validateIssuer(ctx context.Context, upstream *v1
Type: typeOIDCDiscoverySucceeded,
Status: metav1.ConditionFalse,
Reason: reasonUnreachable,
- Message: fmt.Sprintf("failed to perform OIDC discovery against %q:\n%s", upstream.Spec.Issuer, truncateMostLongErr(err)),
+ Message: fmt.Sprintf("failed to perform OIDC discovery against %q:\n%s", upstream.Spec.Issuer, pinnipedcontroller.TruncateMostLongErr(err)),
}
}
@@ -361,7 +361,7 @@ func (c *oidcWatcherController) validateIssuer(ctx context.Context, upstream *v1
Type: typeOIDCDiscoverySucceeded,
Status: metav1.ConditionFalse,
Reason: reasonInvalidResponse,
- Message: fmt.Sprintf("failed to unmarshal OIDC discovery response from %q:\n%s", upstream.Spec.Issuer, truncateMostLongErr(err)),
+ Message: fmt.Sprintf("failed to unmarshal OIDC discovery response from %q:\n%s", upstream.Spec.Issuer, pinnipedcontroller.TruncateMostLongErr(err)),
}
}
if additionalDiscoveryClaims.RevocationEndpoint != "" {
@@ -473,18 +473,6 @@ func computeScopes(additionalScopes []string) []string {
return set.List()
}
-func truncateMostLongErr(err error) string {
- const max = 300
- msg := err.Error()
-
- // always log oidc and x509 errors completely
- if len(msg) <= max || strings.Contains(msg, "oidc:") || strings.Contains(msg, "x509:") {
- return msg
- }
-
- return msg[:max] + fmt.Sprintf(" [truncated %d chars]", len(msg)-max)
-}
-
func validateHTTPSURL(maybeHTTPSURL, endpointType, reason string) (*url.URL, *metav1.Condition) {
parsedURL, err := url.Parse(maybeHTTPSURL)
if err != nil {
@@ -492,7 +480,7 @@ func validateHTTPSURL(maybeHTTPSURL, endpointType, reason string) (*url.URL, *me
Type: typeOIDCDiscoverySucceeded,
Status: metav1.ConditionFalse,
Reason: reason,
- Message: fmt.Sprintf("failed to parse %s URL: %v", endpointType, truncateMostLongErr(err)),
+ Message: fmt.Sprintf("failed to parse %s URL: %v", endpointType, pinnipedcontroller.TruncateMostLongErr(err)),
}
}
if parsedURL.Scheme != "https" {
diff --git a/internal/controller/utilserr.go b/internal/controller/utilserr.go
new file mode 100644
index 000000000..485b2f647
--- /dev/null
+++ b/internal/controller/utilserr.go
@@ -0,0 +1,21 @@
+// Copyright 2024 the Pinniped contributors. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package controller
+
+import (
+ "fmt"
+ "strings"
+)
+
+func TruncateMostLongErr(err error) string {
+ const max = 300
+ msg := err.Error()
+
+ // always log oidc and x509 errors completely
+ if len(msg) <= max || strings.Contains(msg, "oidc:") || strings.Contains(msg, "x509:") {
+ return msg
+ }
+
+ return msg[:max] + fmt.Sprintf(" [truncated %d chars]", len(msg)-max)
+}