diff --git a/lib/auth/webauthn/attestation.go b/lib/auth/webauthn/attestation.go index a382229dce048..fa14c23a21ed1 100644 --- a/lib/auth/webauthn/attestation.go +++ b/lib/auth/webauthn/attestation.go @@ -19,17 +19,22 @@ package webauthn import ( + "context" "crypto/x509" "encoding/pem" + "log/slog" "slices" "github.com/go-webauthn/webauthn/protocol" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" + "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" + logutils "github.com/gravitational/teleport/lib/utils/log" ) +var log = logutils.NewPackageLogger(teleport.ComponentKey, "WebAuthn") + // x5cFormats enumerates all attestation formats that supply an attestation // chain through the "x5c" field. // See https://www.w3.org/TR/webauthn/#sctn-defined-attestation-formats. @@ -138,13 +143,17 @@ func getChainFromX5C(obj protocol.AttestationObject) ([]*x509.Certificate, error // Print out attestation certs if debug is enabled. // This may come in handy for people having trouble with their setups. - if log.IsLevelEnabled(log.DebugLevel) { + ctx := context.Background() + if log.Handler().Enabled(ctx, slog.LevelDebug) { for _, cert := range chain { certPEM := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: cert.Raw, }) - log.Debugf("WebAuthn: got %q attestation certificate:\n\n%s", obj.Format, certPEM) + log.DebugContext(context.Background(), "got attestation certificate", + "format", obj.Format, + "certificate", string(certPEM), + ) } } diff --git a/lib/auth/webauthn/device.go b/lib/auth/webauthn/device.go index a78ec9f7fea4f..700f671b4d264 100644 --- a/lib/auth/webauthn/device.go +++ b/lib/auth/webauthn/device.go @@ -19,6 +19,7 @@ package webauthn import ( + "context" "crypto/ecdsa" "crypto/x509" @@ -26,7 +27,6 @@ import ( "github.com/go-webauthn/webauthn/protocol/webauthncose" wan "github.com/go-webauthn/webauthn/webauthn" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" ) @@ -51,7 +51,7 @@ func deviceToCredential( var err error pubKeyCBOR, err = u2fDERKeyToCBOR(dev.U2F.PubKey) if err != nil { - log.Warnf("WebAuthn: failed to convert U2F device key to CBOR: %v", err) + log.WarnContext(context.Background(), "failed to convert U2F device key to CBOR", "error", err) return wan.Credential{}, false } } diff --git a/lib/auth/webauthn/login.go b/lib/auth/webauthn/login.go index 2ed9f085155a6..9948602beeba6 100644 --- a/lib/auth/webauthn/login.go +++ b/lib/auth/webauthn/login.go @@ -31,7 +31,6 @@ import ( wan "github.com/go-webauthn/webauthn/webauthn" gogotypes "github.com/gogo/protobuf/types" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" mfav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v1" "github.com/gravitational/teleport/api/types" @@ -107,13 +106,14 @@ func (f *loginFlow) begin(ctx context.Context, user string, challengeExtensions continue } - log.Errorf(""+ - "User device %q/%q has unexpected RPID=%q, excluding from allowed credentials. "+ - "RPID changes are not supported by WebAuthn, this is likely to cause permanent authentication problems for your users. "+ - "Consider reverting the change or reset your users so they may register their devices again.", - user, - devices[i].GetName(), - webDev.CredentialRpId) + const msg = "User device has unexpected RPID, excluding from allowed credentials. " + + "RPID changes are not supported by WebAuthn, this is likely to cause permanent authentication problems for your users. " + + "Consider reverting the change or reset your users so they may register their devices again." + log.ErrorContext(ctx, msg, + "user", user, + "device", devices[i].GetName(), + "rpid", webDev.CredentialRpId, + ) // "Cut" device from slice. devices = slices.Delete(devices, i, i+1) @@ -249,7 +249,7 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred origin := parsedResp.Response.CollectedClientData.Origin if err := validateOrigin(origin, f.Webauthn.RPID); err != nil { - log.WithError(err).Debugf("WebAuthn: origin validation failed") + log.DebugContext(ctx, "origin validation failed", "error", err) return nil, trace.Wrap(err) } @@ -330,9 +330,9 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred if (discoverableLogin || uvr == protocol.VerificationRequired) && sd.UserVerification != string(protocol.VerificationRequired) { // This is not a failure yet, but will likely become one. sd.UserVerification = string(protocol.VerificationRequired) - log.Warnf(""+ - "WebAuthn: User verification required by extensions but not by challenge. "+ - "Increased SessionData.UserVerification to %s.", sd.UserVerification) + const msg = "User verification required by extensions but not by challenge. " + + "Increased SessionData.UserVerification." + log.WarnContext(ctx, msg, "user_verification", sd.UserVerification) } sessionData := wantypes.SessionDataToProtocol(sd) @@ -371,8 +371,10 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred return nil, trace.Wrap(err) } if credential.Authenticator.CloneWarning { - log.Warnf( - "WebAuthn: Clone warning detected for user %q / device %q. Device counter may be malfunctioning.", user, dev.GetName()) + log.WarnContext(ctx, "Clone warning detected for device, the device counter may be malfunctioning", + "user", user, + "device", dev.GetName(), + ) } // Update last used timestamp and device counter. @@ -381,7 +383,11 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred } // Retroactively write the credential RPID, now that it cleared authn. if webDev := dev.GetWebauthn(); webDev != nil && webDev.CredentialRpId == "" { - log.Debugf("WebAuthn: Recording RPID=%q in device %q/%q", rpID, user, dev.GetName()) + log.DebugContext(ctx, "Recording RPID in device", + "rpid", rpID, + "user", user, + "device", dev.GetName(), + ) webDev.CredentialRpId = rpID } @@ -395,7 +401,10 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred // passes. if sd.ChallengeExtensions.AllowReuse != mfav1.ChallengeAllowReuse_CHALLENGE_ALLOW_REUSE_YES { if err := f.sessionData.Delete(ctx, user, challenge); err != nil { - log.Warnf("WebAuthn: failed to delete login SessionData for user %v (scope = %s)", user, sd.ChallengeExtensions.Scope) + log.WarnContext(ctx, "failed to delete login SessionData for user", + "user", user, + "scope", sd.ChallengeExtensions.Scope, + ) } } @@ -463,19 +472,19 @@ func updateCredentialAndTimestamps( d.Webauthn.CredentialBackupEligible = &gogotypes.BoolValue{ Value: credential.Flags.BackupEligible, } - log.WithFields(log.Fields{ - "device": dest.GetName(), - "be": credential.Flags.BackupEligible, - }).Debug("Backfilled Webauthn device BE flag") + log.DebugContext(context.Background(), "Backfilled Webauthn device BE flag", + "device", dest.GetName(), + "be", credential.Flags.BackupEligible, + ) } if d.Webauthn.CredentialBackedUp == nil { d.Webauthn.CredentialBackedUp = &gogotypes.BoolValue{ Value: credential.Flags.BackupState, } - log.WithFields(log.Fields{ - "device": dest.GetName(), - "bs": credential.Flags.BackupState, - }).Debug("Backfilled Webauthn device BS flag") + log.DebugContext(context.Background(), "Backfilled Webauthn device BS flag", + "device", dest.GetName(), + "bs", credential.Flags.BackupState, + ) } default: diff --git a/lib/auth/webauthn/register.go b/lib/auth/webauthn/register.go index 50eb3420391eb..9d6a0726af232 100644 --- a/lib/auth/webauthn/register.go +++ b/lib/auth/webauthn/register.go @@ -32,7 +32,6 @@ import ( gogotypes "github.com/gogo/protobuf/types" "github.com/google/uuid" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" @@ -284,7 +283,7 @@ func (f *RegistrationFlow) Finish(ctx context.Context, req RegisterResponse) (*t origin := parsedResp.Response.CollectedClientData.Origin if err := validateOrigin(origin, f.Webauthn.RPID); err != nil { - log.WithError(err).Debugf("WebAuthn: origin validation failed") + log.DebugContext(ctx, "origin validation failed", "error", err) return nil, trace.Wrap(err) } @@ -332,7 +331,7 @@ func (f *RegistrationFlow) Finish(ctx context.Context, req RegisterResponse) (*t protocolErr.Type == protocol.ErrVerification.Type && passwordless && !parsedResp.Response.AttestationObject.AuthData.Flags.UserVerified() { - log.WithError(err).Debug("WebAuthn: Replacing verification error with PIN message") + log.DebugContext(ctx, "WebAuthn: Replacing verification error with PIN message", "error", err) return nil, trace.BadParameter("authenticator doesn't support passwordless, setting up a PIN may fix this") } @@ -378,7 +377,7 @@ func (f *RegistrationFlow) Finish(ctx context.Context, req RegisterResponse) (*t // Registration complete, remove the registration challenge we just used. if err := f.Identity.DeleteWebauthnSessionData(ctx, req.User, scopeSession); err != nil { - log.Warnf("WebAuthn: failed to delete registration SessionData for user %v", req.User) + log.WarnContext(ctx, "failed to delete registration SessionData for user", "user", req.User, "error", err) } return newDevice, nil diff --git a/lib/auth/webauthncli/api.go b/lib/auth/webauthncli/api.go index 8278c77a03634..5ee0f9e4f7d3c 100644 --- a/lib/auth/webauthncli/api.go +++ b/lib/auth/webauthncli/api.go @@ -24,14 +24,20 @@ import ( "strings" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" oteltrace "go.opentelemetry.io/otel/trace" + "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/observability/tracing" "github.com/gravitational/teleport/lib/auth/touchid" wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" wanwin "github.com/gravitational/teleport/lib/auth/webauthnwin" + logutils "github.com/gravitational/teleport/lib/utils/log" +) + +var ( + log = logutils.NewPackageLogger(teleport.ComponentKey, "WebAuthn") + fidoLog = logutils.NewPackageLogger(teleport.ComponentKey, "FIDO2") ) // ErrUsingNonRegisteredDevice is returned from Login when the user attempts to @@ -137,10 +143,10 @@ func Login( switch { case origin == "", assertion == nil: // let downstream handle empty/nil case !strings.HasPrefix(origin, "https://"+assertion.Response.RelyingPartyID): - log.Warnf(""+ - "WebAuthn: origin and RPID mismatch, "+ - "if you are having authentication problems double check your proxy address "+ - "(%q vs %q)", origin, assertion.Response.RelyingPartyID) + log.WarnContext(ctx, "origin and RPID mismatch, if you are having authentication problems double check your proxy address", + "origin", origin, + "rpid", assertion.Response.RelyingPartyID, + ) } var attachment AuthenticatorAttachment @@ -151,7 +157,7 @@ func Login( } if wanwin.IsAvailable() { - log.Debug("WebAuthnWin: Using windows webauthn for credential assertion") + log.DebugContext(ctx, "Using windows webauthn for credential assertion") return wanwin.Login(ctx, origin, assertion, &wanwin.LoginOpts{ AuthenticatorAttachment: wanwin.AuthenticatorAttachment(attachment), }) @@ -159,19 +165,19 @@ func Login( switch attachment { case AttachmentCrossPlatform: - log.Debug("Cross-platform login") + log.DebugContext(ctx, "Cross-platform login") return crossPlatformLogin(ctx, origin, assertion, prompt, opts) case AttachmentPlatform: - log.Debug("Platform login") + log.DebugContext(ctx, "Platform login") return platformLogin(origin, user, assertion, prompt) default: - log.Debug("Attempting platform login") + log.DebugContext(ctx, "Attempting platform login") resp, credentialUser, err := platformLogin(origin, user, assertion, prompt) if !errors.Is(err, &touchid.ErrAttemptFailed{}) { return resp, credentialUser, trace.Wrap(err) } - log.WithError(err).Debug("Platform login failed, falling back to cross-platform") + log.DebugContext(ctx, "Platform login failed, falling back to cross-platform", "error", err) return crossPlatformLogin(ctx, origin, assertion, prompt, opts) } } @@ -180,7 +186,7 @@ func crossPlatformLogin( ctx context.Context, origin string, assertion *wantypes.CredentialAssertion, prompt LoginPrompt, opts *LoginOpts, ) (*proto.MFAAuthenticateResponse, string, error) { - log.Debug("FIDO2: Using libfido2 for assertion") + fidoLog.DebugContext(ctx, "Using libfido2 for assertion") resp, user, err := FIDO2Login(ctx, origin, assertion, prompt, opts) return resp, user, trace.Wrap(err) } @@ -223,11 +229,11 @@ func Register( ctx context.Context, origin string, cc *wantypes.CredentialCreation, prompt RegisterPrompt) (*proto.MFARegisterResponse, error) { if wanwin.IsAvailable() { - log.Debug("WebAuthnWin: Using windows webauthn for credential creation") + log.DebugContext(ctx, "Using windows webauthn for credential creation") return wanwin.Register(ctx, origin, cc) } - log.Debug("FIDO2: Using libfido2 for credential creation") + fidoLog.DebugContext(ctx, "Using libfido2 for credential creation") resp, err := FIDO2Register(ctx, origin, cc, prompt) return resp, trace.Wrap(err) } diff --git a/lib/auth/webauthncli/fido2.go b/lib/auth/webauthncli/fido2.go index a20b714fc2fcb..33a033a26b383 100644 --- a/lib/auth/webauthncli/fido2.go +++ b/lib/auth/webauthncli/fido2.go @@ -29,6 +29,7 @@ import ( "encoding/json" "errors" "fmt" + "log/slog" "sync" "time" @@ -37,7 +38,6 @@ import ( "github.com/go-webauthn/webauthn/protocol/webauthncose" "github.com/gravitational/trace" "github.com/keys-pub/go-libfido2" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/client/proto" wanpb "github.com/gravitational/teleport/api/types/webauthn" @@ -165,7 +165,11 @@ func fido2Login( // Presence of any allowed credential is interpreted as the user identity // being partially established, aka non-passwordless. passwordless := len(allowedCreds) == 0 - log.Debugf("FIDO2: assertion: passwordless=%v, uv=%v, %v allowed credentials", passwordless, uv, len(allowedCreds)) + fidoLog.DebugContext(ctx, "assertion", + "passwordless", passwordless, + "uv", uv, + "allowed_cred_count", len(allowedCreds), + ) // Prepare challenge data for the device. ccdJSON, err := json.Marshal(&CollectedClientData{ @@ -209,7 +213,11 @@ func fido2Login( deviceCallback := func(dev FIDODevice, info *deviceInfo, pin string) error { actualRPID := rpID if usesAppID(dev, info, ccdHash[:], allowedCreds, rpID, appID) { - log.Debugf("FIDO2: Device %v registered for AppID (%q) instead of RPID", info.path, appID) + fidoLog.DebugContext(ctx, "Device registered for AppID instead of RPID", + "device", info.path, + "app_id", appID, + "rp_id", rpID, + ) actualRPID = appID } @@ -227,7 +235,7 @@ func fido2Login( // Happens inconsistently in some authenticator series (YubiKey 5). // We are relying on the fact that, because the PIN is set, the // authenticator will set the UV bit regardless of it being requested. - log.Debugf("FIDO2: Device %v: retrying assertion without UV", info.path) + fidoLog.DebugContext(ctx, "Retrying assertion without UV", "device", info.path) opts.UV = libfido2.Default assertions, err = devAssertion(dev, info, actualRPID, ccdHash[:], allowedCreds, pin, opts) } @@ -239,7 +247,7 @@ func fido2Login( // touch - this causes another slew of problems with abandoned U2F // goroutines during registration. if !info.fido2 { - log.Debugf("FIDO2: U2F device %v not registered, ignoring it", info.path) + fidoLog.DebugContext(ctx, "U2F device not registered, ignoring it", "device", info.path) err = &nonInteractiveError{err: err} } else { err = ErrUsingNonRegisteredDevice // "Upgrade" error message. @@ -248,7 +256,7 @@ func fido2Login( if err != nil { return trace.Wrap(err) } - log.Debugf("FIDO2: Got %v assertions", len(assertions)) + fidoLog.DebugContext(ctx, "Got assertions", "assertion_count", len(assertions)) // Find assertion for target user, or show the prompt. assertion, err := pickAssertion(assertions, prompt, user, passwordless) @@ -256,9 +264,11 @@ func fido2Login( return trace.Wrap(err) } - log.Debugf( - "FIDO2: Authenticated: credential ID (b64) = %v, user ID (hex) = %x, user name = %q", - base64.RawURLEncoding.EncodeToString(assertion.CredentialID), assertion.User.ID, assertion.User.Name) + fidoLog.DebugContext(ctx, "Authenticated", + "credential_id", base64.RawURLEncoding.EncodeToString(assertion.CredentialID), + "user_id", assertion.User.ID, + "user_name", assertion.User.Name, + ) // Use the first successful assertion. // In practice it is very unlikely we'd hit this twice. @@ -342,13 +352,16 @@ func devAssertion( return nil, trace.Wrap(libfido2.ErrUserPresenceRequired) } - if log.IsLevelEnabled(log.DebugLevel) { + if fidoLog.Enabled(context.Background(), slog.LevelDebug) { credPrefix := hex.EncodeToString(cred) const prefixLen = 10 if len(credPrefix) > prefixLen { credPrefix = credPrefix[:prefixLen] } - log.Debugf("FIDO2: Device %v: Using credential %v...", info.path, credPrefix) + fidoLog.DebugContext(context.Background(), "Using credential", + "device", info.path, + "credential", credPrefix, + ) } allowedCreds = [][]byte{cred} @@ -451,7 +464,7 @@ func fido2Register( if err != nil { return nil, trace.Wrap(err) } - log.Debugf("FIDO2: registration: resident key=%v", rrk) + fidoLog.DebugContext(ctx, "registration", "resident_key", rrk) // Can we create ES256 keys? // TODO(codingllama): Consider supporting other algorithms and respecting @@ -526,12 +539,13 @@ func fido2Register( case err != nil: // Swallow unexpected errors: a double registration is better than // aborting the ceremony. - log.Debugf( - "FIDO2: Device %v: excluded credential assertion failed, letting device through: err=%q", - info.path, err) + fidoLog.DebugContext(ctx, "excluded credential assertion failed, letting device through", + "device", info.path, + "error", err, + ) return nil default: - log.Debugf("FIDO2: Device %v: filtered due to presence of excluded credential", info.path) + fidoLog.DebugContext(ctx, "filtered due to presence of excluded credential", "device", info.path) return errHasExcludedCredential } } @@ -619,7 +633,7 @@ func makeAttStatement(attestation *libfido2.Attestation) (string, map[string]int case none: return format, nil, nil default: - log.Debugf(`FIDO2: Unsupported attestation format %q, using "none"`, format) + fidoLog.DebugContext(context.Background(), `Unsupported attestation format, using "none"`, "attestation_format", format) return none, nil, nil } @@ -686,11 +700,11 @@ func runOnFIDO2Devices( case <-devicesC: receiveCount++ case <-maxWait.C: - log.Debugf("FIDO2: Abandoning device goroutines after %s", fido2DeviceMaxWait) + fidoLog.DebugContext(ctx, "Abandoning device goroutines after exceeding wait time", "max_wait_time", fido2DeviceMaxWait) return } } - log.Debug("FIDO2: Device goroutines exited cleanly") + fidoLog.DebugContext(ctx, "Device goroutines exited cleanly") }() // First "interactive" response wins. @@ -701,7 +715,7 @@ func runOnFIDO2Devices( // Keep going on cancels or non-interactive errors. if errors.Is(err, libfido2.ErrKeepaliveCancel) || errors.Is(err, &nonInteractiveError{}) { - log.Debugf("FIDO2: Got cancel or non-interactive device error: %v", err) + fidoLog.DebugContext(ctx, "Got cancel or non-interactive device error", "error", err) continue } @@ -729,7 +743,10 @@ func startDevices( for i, dev := range fidoDevs { path := openDevs[i].path err := dev.Close() - log.Debugf("FIDO2: Close device %v, err=%v", path, err) + fidoLog.DebugContext(context.Background(), "Close device", + "device", path, + "error", err, + ) } } @@ -747,7 +764,10 @@ func startDevices( // This is largely safe to ignore, as opening is fairly consistent in // other situations and failures are likely from a non-chosen device in // multi-device scenarios. - log.Debugf("FIDO2: Device %v failed to open, skipping: %v", path, err) + fidoLog.DebugContext(context.Background(), "Device failed to open, skipping", + "device", path, + "error", err, + ) continue } @@ -828,7 +848,10 @@ func (l *openedDevices) cancelAll(except FIDODevice) { // Note that U2F devices fail Cancel with "invalid argument". err := d.dev.Cancel() - log.Debugf("FIDO2: Cancel device %v, err=%v", d.path, err) + fidoLog.DebugContext(context.Background(), "Cancel device", + "device", d.path, + "error", err, + ) } } @@ -841,10 +864,14 @@ func handleDevice( firstTouchAck func() error, pinPrompt runPrompt, ) error { + ctx := context.Background() // handleDevice owns the device, thus it has the privilege to shut it down. defer func() { err := dev.Close() - log.Debugf("FIDO2: Close device %v, err=%v", path, err) + fidoLog.DebugContext(ctx, "Close device", + "device", path, + "error", err, + ) }() if err := dev.SetTimeout(fido2DeviceTimeout); err != nil { @@ -862,16 +889,22 @@ func handleDevice( if err != nil { return trace.Wrap(&nonInteractiveError{err: err}) } - log.Debugf("FIDO2: Device %v: info %#v", path, info) + fidoLog.DebugContext(ctx, "Device", + "path", path, + "info", info, + ) } else { - log.Debugf("FIDO2: Device %v: not a FIDO2 device", path) + fidoLog.DebugContext(ctx, "not a FIDO2 device", "device", path) } di := makeDevInfo(path, info, isFIDO2) // Apply initial filters, waiting for confirmation if the filter fails before // relaying the error. if err := filter(dev, di); err != nil { - log.Debugf("FIDO2: Device %v filtered, err=%v", path, err) + fidoLog.DebugContext(ctx, "Device filtered", + "device", path, + "error", err, + ) // If the device is chosen then treat the error as interactive. if touched, _ := waitForTouch(dev); touched { @@ -885,7 +918,11 @@ func handleDevice( // Run the callback. cb := withPINHandler(withRetries(deviceCallback)) requiresPIN, err := cb(dev, di, "" /* pin */) - log.Debugf("FIDO2: Device %v: callback returned, requiresPIN=%v, err=%v", path, requiresPIN, err) + fidoLog.DebugContext(ctx, "callback returned", + "device", path, + "requires_pin", requiresPIN, + "error", err, + ) if err != nil { return trace.Wrap(err) } @@ -932,7 +969,11 @@ func devInfo(path string, dev FIDODevice) (*libfido2.DeviceInfo, error) { } lastErr = err - log.Debugf("FIDO2: Device %v: Info failed, retrying after %s: %v", path, fido2RetryInterval, err) + fidoLog.DebugContext(context.Background(), "Info failed, retrying", + "device", path, + "backoff_duration", fido2RetryInterval, + "error", err, + ) time.Sleep(fido2RetryInterval) } @@ -955,7 +996,7 @@ func withRetries(callback deviceCallbackFunc) deviceCallbackFunc { // ErrOperationDenied happens when fingerprint reading fails (UV=false). if errors.Is(err, libfido2.ErrOperationDenied) { fmt.Println("Gesture validation failed, make sure you use a registered fingerprint") - log.Debug("FIDO2: Retrying libfido2 error 'operation denied'") + fidoLog.DebugContext(context.Background(), "Retrying libfido2 error 'operation denied'") continue } @@ -975,7 +1016,7 @@ func withRetries(callback deviceCallbackFunc) deviceCallbackFunc { "Alternatively, you may unblock your device by using it in the Web UI." return trace.Wrap(err, msg) case 63: // FIDO_ERR_UV_INVALID, 0x3f - log.Debug("FIDO2: Retrying libfido2 error 63") + fidoLog.DebugContext(context.Background(), "Retrying libfido2 error 63") continue default: // Unexpected code. return err @@ -1041,7 +1082,7 @@ func waitForTouch(dev FIDODevice) (touched bool, err error) { touch, err := dev.TouchBegin() if err != nil { // Error logged here as it's mostly ignored by callers. - log.Debugf("FIDO2: Device touch begin error: %v", err) + fidoLog.DebugContext(context.Background(), "Device touch begin error", "error", err) return false, trace.Wrap(err) } defer touch.Stop() @@ -1051,7 +1092,7 @@ func waitForTouch(dev FIDODevice) (touched bool, err error) { touched, err := touch.Status(fido2TouchMaxWait) if err != nil { // Error logged here as it's mostly ignored by callers. - log.Debugf("FIDO2: Device touch status error: %v", err) + fidoLog.DebugContext(context.Background(), "Device touch status error", "error", err) return false, trace.Wrap(err) } if touched { diff --git a/lib/auth/webauthnwin/api.go b/lib/auth/webauthnwin/api.go index 4e8de09029911..5d3cdcefe22e5 100644 --- a/lib/auth/webauthnwin/api.go +++ b/lib/auth/webauthnwin/api.go @@ -27,13 +27,13 @@ import ( "context" "fmt" "io" + "log/slog" "os" "sync" "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/protocol/webauthncose" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/client/proto" wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" @@ -221,7 +221,7 @@ type CheckSupportResult struct { func IsAvailable() bool { supports := CheckSupport() if supports.HasCompileSupport && !supports.IsAvailable { - log.Warn("Webauthn is not supported on this version of Windows, supported from version 1903") + slog.WarnContext(context.Background(), "Webauthn is not supported on this version of Windows, supported from version 1903") } return supports.IsAvailable diff --git a/lib/auth/webauthnwin/webauthn_windows.go b/lib/auth/webauthnwin/webauthn_windows.go index 681120739aa92..0f07071ba498e 100644 --- a/lib/auth/webauthnwin/webauthn_windows.go +++ b/lib/auth/webauthnwin/webauthn_windows.go @@ -19,17 +19,19 @@ package webauthnwin import ( + "context" "encoding/base64" "errors" "fmt" + "log/slog" "syscall" "unsafe" "github.com/go-webauthn/webauthn/protocol" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "golang.org/x/sys/windows" + "github.com/gravitational/teleport" wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" ) @@ -52,27 +54,26 @@ func newNativeImpl() *nativeImpl { hasCompileSupport: true, } + logger := slog.With(teleport.ComponentKey, "WebAuthnWin") + ctx := context.Background() + // Explicitly loading the module avoids a panic when calling DLL functions if // the DLL is missing. // https://github.com/gravitational/teleport/issues/36851 if err := modWebAuthn.Load(); err != nil { - log. - WithError(err). - Debug("WebAuthnWin: failed to load WebAuthn.dll (it's likely missing)") + logger.DebugContext(ctx, "failed to load WebAuthn.dll (it's likely missing)", "error", err) return n } // Load WebAuthNGetApiVersionNumber explicitly too, it avoids a panic on some // Windows Server 2019 installs. if err := procWebAuthNGetApiVersionNumber.Find(); err != nil { - log. - WithError(err). - Debug("WebAuthnWin: failed to load WebAuthNGetApiVersionNumber") + logger.DebugContext(ctx, "failed to load WebAuthNGetApiVersionNumber", "error", err) return n } v, err := webAuthNGetApiVersionNumber() if err != nil { - log.WithError(err).Debug("WebAuthnWin: failed to check version") + logger.DebugContext(ctx, "failed to check version", "error", err) return n } n.webauthnAPIVersion = v @@ -86,7 +87,7 @@ func newNativeImpl() *nativeImpl { if err != nil { // This should not happen if dll exists, however we are fine with // to proceed without uvPlatform. - log.WithError(err).Debug("WebAuthnWin: failed to check isUVPlatformAuthenticatorAvailable") + logger.DebugContext(ctx, "failed to check isUVPlatformAuthenticatorAvailable", "error", err) } return n