diff --git a/Dockerfile b/Dockerfile index 360ebbd0f..fffe49f17 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # Copyright 2020-2026 the Pinniped contributors. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -ARG BUILD_IMAGE=golang:1.26.2@sha256:b54cbf583d390341599d7bcbc062425c081105cc5ef6d170ced98ef9d047c716 +ARG BUILD_IMAGE=golang:1.26.3@sha256:8f7c3ac0e4e60fd71e5b66c3e6596079a6dcae1e7e8ebe3143c69de60325b0d1 ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:e3f945647ffb95b5839c07038d64f9811adf17308b9121d8a2b87b6a22a80a39 # Prepare to cross-compile by always running the build stage in the build platform, not the target platform. diff --git a/deploy/supervisor/rbac.yaml b/deploy/supervisor/rbac.yaml index 85a2e9efa..9f0715730 100644 --- a/deploy/supervisor/rbac.yaml +++ b/deploy/supervisor/rbac.yaml @@ -1,4 +1,4 @@ -#! Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. +#! Copyright 2020-2026 the Pinniped contributors. All Rights Reserved. #! SPDX-License-Identifier: Apache-2.0 #@ load("@ytt:data", "data") @@ -142,7 +142,7 @@ rules: resources: [ apiservices ] verbs: [ get, list, patch, update, watch ] - apiGroups: [ admissionregistration.k8s.io ] - resources: [ validatingwebhookconfigurations, mutatingwebhookconfigurations, validatingadmissionpolicies, validatingadmissionpolicybindings ] + resources: [ validatingwebhookconfigurations, mutatingwebhookconfigurations, validatingadmissionpolicies, validatingadmissionpolicybindings, mutatingadmissionpolicies, mutatingadmissionpolicybindings ] verbs: [ get, list, watch ] - apiGroups: [ flowcontrol.apiserver.k8s.io ] resources: [ flowschemas, prioritylevelconfigurations ] diff --git a/go.mod b/go.mod index 1ff9fa102..254ca29a5 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,6 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/ory/fosite v0.49.1-0.20250703093431-a5f0b09bf31c github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c - github.com/pkg/errors v0.9.1 github.com/sclevine/spec v1.4.0 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 @@ -55,13 +54,13 @@ require ( k8s.io/kube-aggregator v0.36.0 k8s.io/kube-openapi v0.0.0-20260505163821-33341827b392 k8s.io/streaming v0.36.0 - k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 + k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 sigs.k8s.io/yaml v1.6.0 ) require ( cel.dev/expr v0.25.1 // indirect - github.com/Azure/go-ntlmssp v0.1.0 // indirect + github.com/Azure/go-ntlmssp v0.1.1 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect @@ -127,6 +126,7 @@ require ( github.com/ory/go-convenience v0.1.0 // indirect github.com/ory/x v0.0.677 // indirect github.com/pelletier/go-toml/v2 v2.0.9 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pquerna/cachecontrol v0.1.0 // indirect github.com/prometheus/client_golang v1.23.2 // indirect diff --git a/go.sum b/go.sum index 4c63258ff..095cc04f8 100644 --- a/go.sum +++ b/go.sum @@ -38,8 +38,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-ntlmssp v0.1.0 h1:DjFo6YtWzNqNvQdrwEyr/e4nhU3vRiwenz5QX7sFz+A= -github.com/Azure/go-ntlmssp v0.1.0/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk= +github.com/Azure/go-ntlmssp v0.1.1 h1:l+FM/EEMb0U9QZE7mKNEDw5Mu3mFiaa2GKOoTSsNDPw= +github.com/Azure/go-ntlmssp v0.1.1/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZYIR/J6A= @@ -1112,8 +1112,8 @@ k8s.io/kube-openapi v0.0.0-20260505163821-33341827b392 h1:B7Ylb1OUptHKVX/3kpvXB0 k8s.io/kube-openapi v0.0.0-20260505163821-33341827b392/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY= k8s.io/streaming v0.36.0 h1:agnTxU+NFulUrtYzXUGKO3ndEa8jKwht1Kwn9nu9x+4= k8s.io/streaming v0.36.0/go.mod h1:z6fV3D+NVkoeqRMtWwlUZK6U17SY/LqNzOxWL6GyR/s= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc= +k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/hack/Dockerfile_fips b/hack/Dockerfile_fips index 735a1e216..23ed64507 100644 --- a/hack/Dockerfile_fips +++ b/hack/Dockerfile_fips @@ -16,7 +16,7 @@ # See https://go.googlesource.com/go/+/dev.boringcrypto/README.boringcrypto.md # and https://kupczynski.info/posts/fips-golang/ for details. -ARG BUILD_IMAGE=golang:1.26.2@sha256:b54cbf583d390341599d7bcbc062425c081105cc5ef6d170ced98ef9d047c716 +ARG BUILD_IMAGE=golang:1.26.3@sha256:8f7c3ac0e4e60fd71e5b66c3e6596079a6dcae1e7e8ebe3143c69de60325b0d1 ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:e3f945647ffb95b5839c07038d64f9811adf17308b9121d8a2b87b6a22a80a39 # This is not currently using --platform to prepare to cross-compile because we use gcc below to build diff --git a/hack/module.sh b/hack/module.sh index 09319e743..745cf8810 100755 --- a/hack/module.sh +++ b/hack/module.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2020-2025 the Pinniped contributors. All Rights Reserved. +# Copyright 2020-2026 the Pinniped contributors. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 set -euo pipefail @@ -46,16 +46,10 @@ function main() { ./hack/module.sh lint ;; 'unittest' | 'unittests' | 'units' | 'unit') - # Temporarily avoid using the race detector for the impersonator package due to https://github.com/kubernetes/kubernetes/issues/128548 KUBE_CACHE_MUTATION_DETECTOR=${kube_cache_mutation_detector} \ KUBE_PANIC_WATCH_DECODE_ERROR=${kube_panic_watch_decode_error} \ CGO_ENABLED=0 \ - go test -short -race $(go list ./... | grep -v internal/concierge/impersonator) - # TODO: change this back to using the race detector everywhere - KUBE_CACHE_MUTATION_DETECTOR=${kube_cache_mutation_detector} \ - KUBE_PANIC_WATCH_DECODE_ERROR=${kube_panic_watch_decode_error} \ - CGO_ENABLED=0 \ - go test -short ./internal/concierge/impersonator + go test -short -race ./... ;; 'generate') go generate ./internal/mocks/... diff --git a/hack/update-go-mod/go.mod b/hack/update-go-mod/go.mod index ad84ecc8c..eb3f460d0 100644 --- a/hack/update-go-mod/go.mod +++ b/hack/update-go-mod/go.mod @@ -2,4 +2,4 @@ module go.pinniped.dev/update-go-mod go 1.25.0 -require golang.org/x/mod v0.34.0 +require golang.org/x/mod v0.35.0 diff --git a/hack/update-go-mod/go.sum b/hack/update-go-mod/go.sum index 47def87f7..662c5241b 100644 --- a/hack/update-go-mod/go.sum +++ b/hack/update-go-mod/go.sum @@ -1,2 +1,2 @@ -golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= -golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= diff --git a/internal/admissionpluginconfig/admissionpluginconfig.go b/internal/admissionpluginconfig/admissionpluginconfig.go index 29eca19ae..fe89b6c5e 100644 --- a/internal/admissionpluginconfig/admissionpluginconfig.go +++ b/internal/admissionpluginconfig/admissionpluginconfig.go @@ -4,10 +4,10 @@ package admissionpluginconfig import ( + "errors" "fmt" "slices" - "github.com/pkg/errors" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" mutatingadmissionpolicy "k8s.io/apiserver/pkg/admission/plugin/policy/mutating" diff --git a/internal/controller/tlsconfigutil/tls_config_util.go b/internal/controller/tlsconfigutil/tls_config_util.go index 2c783db6d..522a33738 100644 --- a/internal/controller/tlsconfigutil/tls_config_util.go +++ b/internal/controller/tlsconfigutil/tls_config_util.go @@ -1,4 +1,4 @@ -// Copyright 2024 the Pinniped contributors. All Rights Reserved. +// Copyright 2024-2026 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package tlsconfigutil @@ -8,7 +8,6 @@ import ( "fmt" "strings" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" corev1informers "k8s.io/client-go/informers/core/v1" @@ -201,7 +200,7 @@ func readCABundleFromK8sSecret(namespace string, name string, key string, secret s, err := secretInformer.Lister().Secrets(namespace).Get(name) if err != nil { - return "", errors.Wrapf(err, "failed to get secret %q", namespacedName) + return "", fmt.Errorf("failed to get secret %q: %w", namespacedName, err) } // For Secrets to be used as a certificate authority data source, the secret should be of type @@ -225,7 +224,7 @@ func readCABundleFromK8sConfigMap(namespace string, name string, key string, con c, err := configMapInformer.Lister().ConfigMaps(namespace).Get(name) if err != nil { - return "", errors.Wrapf(err, "failed to get configmap %q", namespacedName) + return "", fmt.Errorf("failed to get configmap %q: %w", namespacedName, err) } val, exists := c.Data[key] diff --git a/internal/federationdomain/endpoints/token/token_handler.go b/internal/federationdomain/endpoints/token/token_handler.go index 278a94cb5..b0aad3627 100644 --- a/internal/federationdomain/endpoints/token/token_handler.go +++ b/internal/federationdomain/endpoints/token/token_handler.go @@ -1,4 +1,4 @@ -// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // Package token provides a handler for the OIDC token endpoint. @@ -14,7 +14,6 @@ import ( "time" "github.com/ory/fosite" - errorsx "github.com/pkg/errors" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/warning" @@ -165,19 +164,19 @@ func upstreamRefresh( customSessionData := session.Custom if customSessionData == nil { - return errorsx.WithStack(errMissingUpstreamSessionInternalError()) + return errMissingUpstreamSessionInternalError() } providerName := customSessionData.ProviderName providerType := customSessionData.ProviderType providerUID := customSessionData.ProviderUID if providerUID == "" || providerName == "" { - return errorsx.WithStack(errMissingUpstreamSessionInternalError()) + return errMissingUpstreamSessionInternalError() } skipGroups := !slices.Contains(accessRequest.GetGrantedScopes(), oidcapi.ScopeGroups) if session.IDTokenClaims().AuthTime.IsZero() { - return errorsx.WithStack(resolvedprovider.ErrMissingUpstreamSessionInternalError()) + return resolvedprovider.ErrMissingUpstreamSessionInternalError() } err := validateSessionHasUsername(session) @@ -201,7 +200,7 @@ func upstreamRefresh( cloneOfIDPSpecificSessionData := idp.CloneIDPSpecificSessionDataFromSession(session.Custom) if cloneOfIDPSpecificSessionData == nil { - return errorsx.WithStack(resolvedprovider.ErrMissingUpstreamSessionInternalError()) + return resolvedprovider.ErrMissingUpstreamSessionInternalError() } oldUntransformedUsername := session.Custom.UpstreamUsername @@ -299,21 +298,21 @@ func findProviderByNameAndType( for _, p := range idpLister.GetIdentityProviders() { if p.GetSessionProviderType() == providerType && p.GetProvider().GetResourceName() == providerResourceName { if p.GetProvider().GetResourceUID() != mustHaveResourceUID { - return nil, errorsx.WithStack(errUpstreamRefreshError().WithHint( - "Provider from upstream session data has changed its resource UID since authentication.")) + return nil, errUpstreamRefreshError().WithHint( + "Provider from upstream session data has changed its resource UID since authentication.") } return p, nil } } - return nil, errorsx.WithStack(errUpstreamRefreshError(). + return nil, errUpstreamRefreshError(). WithHint("Provider from upstream session data was not found."). - WithDebugf("provider name: %q, provider type: %q", providerResourceName, providerType)) + WithDebugf("provider name: %q, provider type: %q", providerResourceName, providerType) } func validateSessionHasUsername(session *psession.PinnipedSession) error { downstreamUsername := session.Custom.Username if len(downstreamUsername) == 0 { - return errorsx.WithStack(errMissingUpstreamSessionInternalError()) + return errMissingUpstreamSessionInternalError() } return nil } @@ -348,22 +347,22 @@ func applyIdentityTransformationsDuringRefresh( func validateAndGetDownstreamGroupsFromSession(session *psession.PinnipedSession) ([]string, error) { extra := session.Fosite.Claims.Extra if extra == nil { - return nil, errorsx.WithStack(errMissingUpstreamSessionInternalError()) + return nil, errMissingUpstreamSessionInternalError() } downstreamGroupsInterface := extra[oidcapi.IDTokenClaimGroups] if downstreamGroupsInterface == nil { - return nil, errorsx.WithStack(errMissingUpstreamSessionInternalError()) + return nil, errMissingUpstreamSessionInternalError() } downstreamGroupsInterfaceList, ok := downstreamGroupsInterface.([]any) if !ok { - return nil, errorsx.WithStack(errMissingUpstreamSessionInternalError()) + return nil, errMissingUpstreamSessionInternalError() } downstreamGroups := make([]string, 0, len(downstreamGroupsInterfaceList)) for _, downstreamGroupInterface := range downstreamGroupsInterfaceList { downstreamGroup, ok := downstreamGroupInterface.(string) if !ok || len(downstreamGroup) == 0 { - return nil, errorsx.WithStack(errMissingUpstreamSessionInternalError()) + return nil, errMissingUpstreamSessionInternalError() } downstreamGroups = append(downstreamGroups, downstreamGroup) } diff --git a/internal/federationdomain/endpoints/token/token_handler_test.go b/internal/federationdomain/endpoints/token/token_handler_test.go index 76d742863..091ca93a9 100644 --- a/internal/federationdomain/endpoints/token/token_handler_test.go +++ b/internal/federationdomain/endpoints/token/token_handler_test.go @@ -13,6 +13,7 @@ import ( "encoding/base32" "encoding/base64" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -30,7 +31,6 @@ import ( "github.com/ory/fosite/handler/openid" fositepkce "github.com/ory/fosite/handler/pkce" fositejwt "github.com/ory/fosite/token/jwt" - "github.com/pkg/errors" "github.com/stretchr/testify/require" "golang.org/x/crypto/bcrypt" "golang.org/x/oauth2" diff --git a/internal/federationdomain/endpoints/tokenexchange/token_exchange.go b/internal/federationdomain/endpoints/tokenexchange/token_exchange.go index d68e73def..822f59f93 100644 --- a/internal/federationdomain/endpoints/tokenexchange/token_exchange.go +++ b/internal/federationdomain/endpoints/tokenexchange/token_exchange.go @@ -1,4 +1,4 @@ -// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package tokenexchange @@ -11,7 +11,6 @@ import ( "github.com/ory/fosite" fositeoauth2 "github.com/ory/fosite/handler/oauth2" "github.com/ory/fosite/handler/openid" - "github.com/pkg/errors" oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc" "go.pinniped.dev/internal/psession" @@ -48,44 +47,44 @@ var _ fosite.TokenEndpointHandler = (*tokenExchangeHandler)(nil) func (t *tokenExchangeHandler) HandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) error { // Skip this request if it's for a different grant type. if !t.CanHandleTokenEndpointRequest(ctx, requester) { - return errors.WithStack(fosite.ErrUnknownRequest) + return fosite.ErrUnknownRequest } // Validate the basic RFC8693 parameters we support. params, err := t.validateParams(requester.GetRequestForm()) if err != nil { - return errors.WithStack(err) + return err } // Validate the incoming access token and lookup the information about the original authorize request from storage. originalRequester, err := t.validateAccessToken(ctx, requester, params.subjectAccessToken) if err != nil { - return errors.WithStack(err) + return err } // Check that the currently authenticated client and the client which was originally used to get the access token are the same. if originalRequester.GetClient().GetID() != requester.GetClient().GetID() { // This error message is copied from the similar check in fosite's flow_authorize_code_token.go. - return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the one from the authorize request.")) + return fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the one from the authorize request.") } // Check that the client is allowed to perform this grant type. if !requester.GetClient().GetGrantTypes().Has(oidcapi.GrantTypeTokenExchange) { // This error message is trying to be similar to the analogous one in fosite's flow_authorize_code_token.go. - return errors.WithStack(fosite.ErrUnauthorizedClient.WithHintf(`The OAuth 2.0 Client is not allowed to use token exchange grant "%s".`, oidcapi.GrantTypeTokenExchange)) + return fosite.ErrUnauthorizedClient.WithHintf(`The OAuth 2.0 Client is not allowed to use token exchange grant "%s".`, oidcapi.GrantTypeTokenExchange) } // Require that the incoming access token has the pinniped:request-audience and OpenID scopes. if !originalRequester.GetGrantedScopes().Has(oidcapi.ScopeRequestAudience) { - return errors.WithStack(fosite.ErrAccessDenied.WithHintf("Missing the %q scope.", oidcapi.ScopeRequestAudience)) + return fosite.ErrAccessDenied.WithHintf("Missing the %q scope.", oidcapi.ScopeRequestAudience) } if !originalRequester.GetGrantedScopes().Has(oidcapi.ScopeOpenID) { - return errors.WithStack(fosite.ErrAccessDenied.WithHintf("Missing the %q scope.", oidcapi.ScopeOpenID)) + return fosite.ErrAccessDenied.WithHintf("Missing the %q scope.", oidcapi.ScopeOpenID) } // Check that the stored session meets the minimum requirements for token exchange. if err := t.validateSession(originalRequester); err != nil { - return errors.WithStack(err) + return err } // Copy the original session ID from storage. @@ -102,7 +101,7 @@ func (t *tokenExchangeHandler) HandleTokenEndpointRequest(ctx context.Context, r func (t *tokenExchangeHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { // Skip this request if it's for a different grant type. if !t.CanHandleTokenEndpointRequest(ctx, requester) { - return errors.WithStack(fosite.ErrUnknownRequest) + return fosite.ErrUnknownRequest } // Get the requested audience parameter again, which was already validated by HandleTokenEndpointRequest() above. @@ -111,7 +110,7 @@ func (t *tokenExchangeHandler) PopulateTokenEndpointResponse(ctx context.Context // Use the original authorize request information, along with the requested audience, to mint a new JWT. responseToken, err := t.mintJWT(ctx, requester, requestedNewAudience) if err != nil { - return errors.WithStack(err) + return err } // Format the response parameters according to RFC8693. @@ -212,7 +211,7 @@ func (t *tokenExchangeHandler) validateAccessToken(ctx context.Context, requeste } // Validate the access token using its stored session data, which includes its expiration time. if err := t.accessTokenStrategy.ValidateAccessToken(ctx, originalRequester, accessToken); err != nil { - return nil, errors.WithStack(err) + return nil, err } return originalRequester, nil } diff --git a/internal/federationdomain/oidc/oidc.go b/internal/federationdomain/oidc/oidc.go index 7ebf8c920..576d3c170 100644 --- a/internal/federationdomain/oidc/oidc.go +++ b/internal/federationdomain/oidc/oidc.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // Package oidc contains common OIDC functionality needed by FederationDomains to implement @@ -8,7 +8,6 @@ package oidc import ( "crypto/subtle" "errors" - "fmt" "net/http" "reflect" "time" @@ -16,7 +15,6 @@ import ( "github.com/felixge/httpsnoop" "github.com/ory/fosite" "github.com/ory/fosite/compose" - errorsx "github.com/pkg/errors" oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc" "go.pinniped.dev/internal/federationdomain/clientregistry" @@ -402,18 +400,7 @@ func validateCSRFValue(state *UpstreamStateParamData, csrfCookieValue csrftoken. // WriteAuthorizeError writes an authorization error as it should be returned by the authorization endpoint and other // similar endpoints that are the end of the downstream authcode flow. Errors responses are written in the usual fosite style. func WriteAuthorizeError(r *http.Request, w http.ResponseWriter, oauthHelper fosite.OAuth2Provider, authorizeRequester fosite.AuthorizeRequester, err error, isBrowserless bool) { - if plog.Enabled(plog.LevelTrace) { - // When trace level logging is enabled, include the stack trace in the log message. - keysAndValues := FositeErrorForLog(err) - errWithStack := errorsx.WithStack(err) - keysAndValues = append(keysAndValues, "errWithStack") - // klog always prints error values using %s, which does not include stack traces, - // so convert the error to a string which includes the stack trace here. - keysAndValues = append(keysAndValues, fmt.Sprintf("%+v", errWithStack)) - plog.Trace("authorize response error", keysAndValues...) - } else { - plog.Info("authorize response error", FositeErrorForLog(err)...) - } + plog.Info("authorize response error", FositeErrorForLog(err)...) if isBrowserless { w = rewriteStatusSeeOtherToStatusFoundForBrowserless(w) } diff --git a/internal/federationdomain/resolvedprovider/resolvedldap/resolved_ldap_provider.go b/internal/federationdomain/resolvedprovider/resolvedldap/resolved_ldap_provider.go index 5a989f31a..e07ebc8fa 100644 --- a/internal/federationdomain/resolvedprovider/resolvedldap/resolved_ldap_provider.go +++ b/internal/federationdomain/resolvedprovider/resolvedldap/resolved_ldap_provider.go @@ -1,4 +1,4 @@ -// Copyright 2024 the Pinniped contributors. All Rights Reserved. +// Copyright 2024-2026 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package resolvedldap @@ -9,7 +9,6 @@ import ( "net/http" "github.com/ory/fosite" - errorsx "github.com/pkg/errors" "go.pinniped.dev/generated/latest/apis/supervisor/idpdiscovery/v1alpha1" "go.pinniped.dev/internal/authenticators" @@ -193,7 +192,7 @@ func (p *FederationDomainResolvedLDAPIdentityProvider) UpstreamRefresh( sessionData, ok := identity.IDPSpecificSessionData.(*psession.LDAPSessionData) if !ok { // This shouldn't really happen. - return nil, errorsx.WithStack(resolvedprovider.ErrMissingUpstreamSessionInternalError()) + return nil, resolvedprovider.ErrMissingUpstreamSessionInternalError() } dn = sessionData.UserDN additionalAttributes = sessionData.ExtraRefreshAttributes @@ -201,7 +200,7 @@ func (p *FederationDomainResolvedLDAPIdentityProvider) UpstreamRefresh( sessionData, ok := identity.IDPSpecificSessionData.(*psession.ActiveDirectorySessionData) if !ok { // This shouldn't really happen. - return nil, errorsx.WithStack(resolvedprovider.ErrMissingUpstreamSessionInternalError()) + return nil, resolvedprovider.ErrMissingUpstreamSessionInternalError() } dn = sessionData.UserDN additionalAttributes = sessionData.ExtraRefreshAttributes @@ -215,7 +214,7 @@ func (p *FederationDomainResolvedLDAPIdentityProvider) UpstreamRefresh( } if dn == "" { - return nil, errorsx.WithStack(resolvedprovider.ErrMissingUpstreamSessionInternalError()) + return nil, resolvedprovider.ErrMissingUpstreamSessionInternalError() } plog.Debug("attempting upstream refresh request", diff --git a/internal/federationdomain/resolvedprovider/resolvedoidc/resolved_oidc_provider.go b/internal/federationdomain/resolvedprovider/resolvedoidc/resolved_oidc_provider.go index 4d37db44e..e037e182b 100644 --- a/internal/federationdomain/resolvedprovider/resolvedoidc/resolved_oidc_provider.go +++ b/internal/federationdomain/resolvedprovider/resolvedoidc/resolved_oidc_provider.go @@ -12,7 +12,6 @@ import ( "time" "github.com/ory/fosite" - errorsx "github.com/pkg/errors" "golang.org/x/oauth2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -228,7 +227,7 @@ func (p *FederationDomainResolvedOIDCIdentityProvider) UpstreamRefresh( sessionData, ok := identity.IDPSpecificSessionData.(*psession.OIDCSessionData) if !ok { // This shouldn't really happen. - return nil, errorsx.WithStack(resolvedprovider.ErrMissingUpstreamSessionInternalError()) + return nil, resolvedprovider.ErrMissingUpstreamSessionInternalError() } accessTokenStored := sessionData.UpstreamAccessToken != "" @@ -237,7 +236,7 @@ func (p *FederationDomainResolvedOIDCIdentityProvider) UpstreamRefresh( //nolint:staticcheck // De Morgan's doesn't make this more readable exactlyOneTokenStored := (accessTokenStored || refreshTokenStored) && !(accessTokenStored && refreshTokenStored) if !exactlyOneTokenStored { - return nil, errorsx.WithStack(resolvedprovider.ErrMissingUpstreamSessionInternalError()) + return nil, resolvedprovider.ErrMissingUpstreamSessionInternalError() } plog.Debug("attempting upstream refresh request", diff --git a/internal/federationdomain/strategy/dynamic_oauth2_hmac_strategy.go b/internal/federationdomain/strategy/dynamic_oauth2_hmac_strategy.go index ee432d439..7a9d12ff7 100644 --- a/internal/federationdomain/strategy/dynamic_oauth2_hmac_strategy.go +++ b/internal/federationdomain/strategy/dynamic_oauth2_hmac_strategy.go @@ -1,4 +1,4 @@ -// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package strategy @@ -10,7 +10,6 @@ import ( "github.com/ory/fosite" "github.com/ory/fosite/compose" fositeoauth2 "github.com/ory/fosite/handler/oauth2" - errorsx "github.com/pkg/errors" "go.pinniped.dev/internal/federationdomain/storage" ) @@ -72,8 +71,7 @@ func (s *DynamicOauth2HMACStrategy) GenerateAccessToken( if err == nil { if !strings.HasPrefix(token, oryAccessTokenPrefix) { // This would only happen if fosite changed how it generates tokens. Defensive programming here. - return "", "", errorsx.WithStack(fosite.ErrInvalidTokenFormat. - WithDebugf("Generated token does not have expected prefix")) + return "", "", fosite.ErrInvalidTokenFormat.WithDebugf("Generated token does not have expected prefix") } token = replacePrefix(token, oryAccessTokenPrefix, pinAccessTokenPrefix) } @@ -86,8 +84,7 @@ func (s *DynamicOauth2HMACStrategy) ValidateAccessToken( token string, ) error { if !strings.HasPrefix(token, pinAccessTokenPrefix) { - return errorsx.WithStack(fosite.ErrInvalidTokenFormat. - WithDebugf("Access token did not have prefix %q", pinAccessTokenPrefix)) + return fosite.ErrInvalidTokenFormat.WithDebugf("Access token did not have prefix %q", pinAccessTokenPrefix) } return s.delegate().ValidateAccessToken(ctx, requester, replacePrefix(token, pinAccessTokenPrefix, oryAccessTokenPrefix)) } @@ -104,8 +101,7 @@ func (s *DynamicOauth2HMACStrategy) GenerateRefreshToken( if err == nil { if !strings.HasPrefix(token, oryRefreshTokenPrefix) { // This would only happen if fosite changed how it generates tokens. Defensive programming here. - return "", "", errorsx.WithStack(fosite.ErrInvalidTokenFormat. - WithDebugf("Generated token does not have expected prefix")) + return "", "", fosite.ErrInvalidTokenFormat.WithDebugf("Generated token does not have expected prefix") } token = replacePrefix(token, oryRefreshTokenPrefix, pinRefreshTokenPrefix) } @@ -118,8 +114,7 @@ func (s *DynamicOauth2HMACStrategy) ValidateRefreshToken( token string, ) error { if !strings.HasPrefix(token, pinRefreshTokenPrefix) { - return errorsx.WithStack(fosite.ErrInvalidTokenFormat. - WithDebugf("Refresh token did not have prefix %q", pinRefreshTokenPrefix)) + return fosite.ErrInvalidTokenFormat.WithDebugf("Refresh token did not have prefix %q", pinRefreshTokenPrefix) } return s.delegate().ValidateRefreshToken(ctx, requester, replacePrefix(token, pinRefreshTokenPrefix, oryRefreshTokenPrefix)) } @@ -136,8 +131,7 @@ func (s *DynamicOauth2HMACStrategy) GenerateAuthorizeCode( if err == nil { if !strings.HasPrefix(authcode, oryAuthcodePrefix) { // This would only happen if fosite changed how it generates tokens. Defensive programming here. - return "", "", errorsx.WithStack(fosite.ErrInvalidTokenFormat. - WithDebugf("Generated token does not have expected prefix")) + return "", "", fosite.ErrInvalidTokenFormat.WithDebugf("Generated token does not have expected prefix") } authcode = replacePrefix(authcode, oryAuthcodePrefix, pinAuthcodePrefix) } @@ -150,8 +144,7 @@ func (s *DynamicOauth2HMACStrategy) ValidateAuthorizeCode( token string, ) error { if !strings.HasPrefix(token, pinAuthcodePrefix) { - return errorsx.WithStack(fosite.ErrInvalidTokenFormat. - WithDebugf("Authorization code did not have prefix %q", pinAuthcodePrefix)) + return fosite.ErrInvalidTokenFormat.WithDebugf("Authorization code did not have prefix %q", pinAuthcodePrefix) } return s.delegate().ValidateAuthorizeCode(ctx, requester, replacePrefix(token, pinAuthcodePrefix, oryAuthcodePrefix)) } diff --git a/internal/fositestorage/accesstoken/accesstoken_test.go b/internal/fositestorage/accesstoken/accesstoken_test.go index 48d19191c..dd2853789 100644 --- a/internal/fositestorage/accesstoken/accesstoken_test.go +++ b/internal/fositestorage/accesstoken/accesstoken_test.go @@ -5,6 +5,7 @@ package accesstoken import ( "context" + "errors" "net/url" "testing" "time" @@ -12,7 +13,6 @@ import ( "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" fositejwt "github.com/ory/fosite/token/jwt" - "github.com/pkg/errors" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/internal/fositestorage/authorizationcode/authorizationcode_test.go b/internal/fositestorage/authorizationcode/authorizationcode_test.go index 2c1c62a90..d99898b53 100644 --- a/internal/fositestorage/authorizationcode/authorizationcode_test.go +++ b/internal/fositestorage/authorizationcode/authorizationcode_test.go @@ -8,6 +8,7 @@ import ( "crypto/ed25519" "crypto/x509" "encoding/json" + "errors" "fmt" "math/rand" "net/url" @@ -21,7 +22,6 @@ import ( fositeoauth2 "github.com/ory/fosite/handler/oauth2" "github.com/ory/fosite/handler/openid" fositejwt "github.com/ory/fosite/token/jwt" - "github.com/pkg/errors" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" diff --git a/internal/fositestorage/openidconnect/openidconnect_test.go b/internal/fositestorage/openidconnect/openidconnect_test.go index b4b3094b0..8b3e4e475 100644 --- a/internal/fositestorage/openidconnect/openidconnect_test.go +++ b/internal/fositestorage/openidconnect/openidconnect_test.go @@ -1,17 +1,17 @@ -// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package openidconnect import ( "context" + "errors" "net/url" "testing" "time" "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" - "github.com/pkg/errors" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/internal/fositestorage/pkce/pkce_test.go b/internal/fositestorage/pkce/pkce_test.go index 98ed1b1e1..1dbd9023f 100644 --- a/internal/fositestorage/pkce/pkce_test.go +++ b/internal/fositestorage/pkce/pkce_test.go @@ -1,17 +1,17 @@ -// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package pkce import ( "context" + "errors" "net/url" "testing" "time" "github.com/ory/fosite" "github.com/ory/fosite/handler/pkce" - "github.com/pkg/errors" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/internal/fositestorage/refreshtoken/refreshtoken_test.go b/internal/fositestorage/refreshtoken/refreshtoken_test.go index 1fd11c91e..fcba4c3c0 100644 --- a/internal/fositestorage/refreshtoken/refreshtoken_test.go +++ b/internal/fositestorage/refreshtoken/refreshtoken_test.go @@ -5,6 +5,7 @@ package refreshtoken import ( "context" + "errors" "net/url" "testing" "time" @@ -12,7 +13,6 @@ import ( "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" fositejwt "github.com/ory/fosite/token/jwt" - "github.com/pkg/errors" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/internal/tokenclient/tokenclient.go b/internal/tokenclient/tokenclient.go index a6d27e68b..d831f10bc 100644 --- a/internal/tokenclient/tokenclient.go +++ b/internal/tokenclient/tokenclient.go @@ -1,13 +1,14 @@ -// Copyright 2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2023-2026 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package tokenclient import ( "context" + "errors" + "fmt" "time" - "github.com/pkg/errors" authenticationv1 "k8s.io/api/authentication/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" @@ -122,7 +123,7 @@ func (tc TokenClient) fetchToken(ctx context.Context) (token string, ttl time.Du ) if err != nil { - return "", 0, errors.Wrap(err, "error creating token") + return "", 0, fmt.Errorf("error creating token: %w", err) } if tokenResponse == nil { diff --git a/test/integration/concierge_impersonation_proxy_test.go b/test/integration/concierge_impersonation_proxy_test.go index b6f35d7c3..338cd52bf 100644 --- a/test/integration/concierge_impersonation_proxy_test.go +++ b/test/integration/concierge_impersonation_proxy_test.go @@ -589,11 +589,8 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl _, err = nestedImpersonationClient.Kubernetes.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyTLSSecretName(env), metav1.GetOptions{}) // this user is not allowed to impersonate other users require.True(t, apierrors.IsForbidden(err), err) - require.EqualError(t, err, fmt.Sprintf( - `secrets "%s" is forbidden: `+ - `User "%s" cannot impersonate-on:user-info:get resource "secrets" in API group "" in the namespace "%s": `+ - `decision made by impersonation-proxy.concierge.pinniped.dev`, - impersonationProxyTLSSecretName(env), env.TestUser.ExpectedUsername, env.ConciergeNamespace)) + require.Contains(t, err.Error(), fmt.Sprintf(`is forbidden: User "%s" cannot impersonate`, env.TestUser.ExpectedUsername)) + require.Contains(t, err.Error(), `decision made by impersonation-proxy.concierge.pinniped.dev`) // impersonate the GC service account instead which can read anything (the binding to edit allows this) nestedImpersonationClientAsSA, credentialsAsSA := newImpersonationProxyClient(t, impersonationProxyURL, impersonationProxyCACertPEM,