Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions lib/client/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,20 @@ func WithBeforeLoginHook(fn func() error) RetryWithReloginOption {

// IsErrorResolvableWithRelogin returns true if relogin is attempted on `err`.
func IsErrorResolvableWithRelogin(err error) bool {
// Private key policy errors indicate that the user must login with an
// unexpected private key policy requirement satisfied. This can occur
// in the following cases:
// - User is logging in for the first time, and their strictest private
// key policy requirement is specified in a role.
// - User is assuming a role with a stricter private key policy requirement
// than the user's given roles.
// - The private key policy in the user's roles or the cluster auth
// preference have been upgraded since the user last logged in, making
// their current login session invalid.
if keys.IsPrivateKeyPolicyError(err) {
return true
}

// Ignore any failures resulting from RPCs.
// These were all materialized as status.Error here before
// https://github.com/gravitational/teleport/pull/30578.
Expand All @@ -640,11 +654,10 @@ func IsErrorResolvableWithRelogin(err error) bool {
return false
}

return keys.IsPrivateKeyPolicyError(err) ||
// TODO(codingllama): Retrying BadParameter is a terrible idea.
// We should fix this and remove the RemoteError condition above as well.
// Any retriable error should be explicitly marked as such.
trace.IsBadParameter(err) ||
// TODO(codingllama): Retrying BadParameter is a terrible idea.
// We should fix this and remove the RemoteError condition above as well.
// Any retriable error should be explicitly marked as such.
return trace.IsBadParameter(err) ||
trace.IsTrustError(err) ||
utils.IsCertExpiredError(err) ||
// Assume that failed handshake is a result of expired credentials.
Expand Down
31 changes: 31 additions & 0 deletions lib/client/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import (

"github.com/gravitational/teleport/api/client/webclient"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/utils/grpc/interceptors"
"github.com/gravitational/teleport/api/utils/keys"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/events"
"github.com/gravitational/teleport/lib/observability/tracing"
Expand Down Expand Up @@ -1168,3 +1170,32 @@ func TestConnectToProxyCancelledContext(t *testing.T) {
require.Nil(t, proxy)
require.Error(t, err)
}

func TestIsErrorResolvableWithRelogin(t *testing.T) {
for _, tt := range []struct {
name string
err error
expectResolvable bool
}{
{
name: "private key policy error should be resolvable",
err: keys.NewPrivateKeyPolicyError(keys.PrivateKeyPolicyHardwareKey),
expectResolvable: true,
}, {
name: "wrapped private key policy error should be resolvable",
err: &interceptors.RemoteError{
Err: keys.NewPrivateKeyPolicyError(keys.PrivateKeyPolicyHardwareKey),
},
expectResolvable: true,
},
} {
t.Run(tt.name, func(t *testing.T) {
resolvable := IsErrorResolvableWithRelogin(tt.err)
if tt.expectResolvable {
require.True(t, resolvable, "Expected error to be resolvable with relogin")
} else {
require.False(t, resolvable, "Expected error to be unresolvable with relogin")
}
})
}
}