diff --git a/go.mod b/go.mod index 3f425a86b..fce0f37ff 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 @@ -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/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/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)) }