mirror of
https://github.com/miniflux/v2.git
synced 2025-06-27 16:36:00 +00:00
fix(webauthn): add backup eligibility flag workaround to avoid a 401
Since go-webauthn v0.11.0, the backup eligibility flag is strictly validated, but Miniflux does not store this flag. This workaround to set the flag based on the parsed response, and avoid "BackupEligible flag inconsistency detected during login validation" error. See https://github.com/go-webauthn/webauthn/pull/240
This commit is contained in:
parent
ea4d0a4f72
commit
2bcc4b8399
1 changed files with 46 additions and 10 deletions
|
@ -206,6 +206,15 @@ func (h *handler) finishLogin(w http.ResponseWriter, r *http.Request) {
|
|||
json.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
slog.Debug("WebAuthn: parsed response flags",
|
||||
slog.Bool("user_present", parsedResponse.Response.AuthenticatorData.Flags.HasUserPresent()),
|
||||
slog.Bool("user_verified", parsedResponse.Response.AuthenticatorData.Flags.HasUserPresent()),
|
||||
slog.Bool("has_attested_credential_data", parsedResponse.Response.AuthenticatorData.Flags.HasAttestedCredentialData()),
|
||||
slog.Bool("has_backup_eligible", parsedResponse.Response.AuthenticatorData.Flags.HasBackupEligible()),
|
||||
slog.Bool("has_backup_state", parsedResponse.Response.AuthenticatorData.Flags.HasBackupState()),
|
||||
)
|
||||
|
||||
sessionData := request.WebAuthnSessionData(r)
|
||||
|
||||
var user *model.User
|
||||
|
@ -218,34 +227,54 @@ func (h *handler) finishLogin(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
var cred *model.WebAuthnCredential
|
||||
var matchingCredential *model.WebAuthnCredential
|
||||
if user != nil {
|
||||
creds, err := h.store.WebAuthnCredentialsByUserID(user.ID)
|
||||
storedCredentials, err := h.store.WebAuthnCredentialsByUserID(user.ID)
|
||||
if err != nil {
|
||||
json.ServerError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
sessionData.SessionData.UserID = parsedResponse.Response.UserHandle
|
||||
credCredential, err := web.ValidateLogin(WebAuthnUser{user, parsedResponse.Response.UserHandle, creds}, *sessionData.SessionData, parsedResponse)
|
||||
webAuthUser := WebAuthnUser{user, parsedResponse.Response.UserHandle, storedCredentials}
|
||||
|
||||
// Since go-webauthn v0.11.0, the backup eligibility flag is strictly validated, but Miniflux does not store this flag.
|
||||
// This workaround set the flag based on the parsed response, and avoid "BackupEligible flag inconsistency detected during login validation" error.
|
||||
// See https://github.com/go-webauthn/webauthn/pull/240
|
||||
for index := range webAuthUser.Credentials {
|
||||
webAuthUser.Credentials[index].Credential.Flags.BackupEligible = parsedResponse.Response.AuthenticatorData.Flags.HasBackupEligible()
|
||||
}
|
||||
|
||||
for _, webAuthCredential := range webAuthUser.WebAuthnCredentials() {
|
||||
slog.Debug("WebAuthn: stored credential flags",
|
||||
slog.Bool("user_present", webAuthCredential.Flags.UserPresent),
|
||||
slog.Bool("user_verified", webAuthCredential.Flags.UserVerified),
|
||||
slog.Bool("backup_eligible", webAuthCredential.Flags.BackupEligible),
|
||||
slog.Bool("backup_state", webAuthCredential.Flags.BackupState),
|
||||
)
|
||||
}
|
||||
|
||||
credCredential, err := web.ValidateLogin(webAuthUser, *sessionData.SessionData, parsedResponse)
|
||||
if err != nil {
|
||||
slog.Warn("WebAuthn: ValidateLogin failed", slog.Any("error", err))
|
||||
json.Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
for _, credTest := range creds {
|
||||
if bytes.Equal(credCredential.ID, credTest.Credential.ID) {
|
||||
cred = &credTest
|
||||
for _, storedCredential := range storedCredentials {
|
||||
if bytes.Equal(credCredential.ID, storedCredential.Credential.ID) {
|
||||
matchingCredential = &storedCredential
|
||||
}
|
||||
}
|
||||
|
||||
if cred == nil {
|
||||
if matchingCredential == nil {
|
||||
json.ServerError(w, r, fmt.Errorf("no matching credential for %v", credCredential))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
userByHandle := func(rawID, userHandle []byte) (webauthn.User, error) {
|
||||
var uid int64
|
||||
uid, cred, err = h.store.WebAuthnCredentialByHandle(userHandle)
|
||||
uid, matchingCredential, err = h.store.WebAuthnCredentialByHandle(userHandle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -259,11 +288,18 @@ func (h *handler) finishLogin(w http.ResponseWriter, r *http.Request) {
|
|||
if user == nil {
|
||||
return nil, fmt.Errorf("no user found for handle %x", userHandle)
|
||||
}
|
||||
return WebAuthnUser{user, userHandle, []model.WebAuthnCredential{*cred}}, nil
|
||||
|
||||
// Since go-webauthn v0.11.0, the backup eligibility flag is strictly validated, but Miniflux does not store this flag.
|
||||
// This workaround set the flag based on the parsed response, and avoid "BackupEligible flag inconsistency detected during login validation" error.
|
||||
// See https://github.com/go-webauthn/webauthn/pull/240
|
||||
matchingCredential.Credential.Flags.BackupEligible = parsedResponse.Response.AuthenticatorData.Flags.HasBackupEligible()
|
||||
|
||||
return WebAuthnUser{user, userHandle, []model.WebAuthnCredential{*matchingCredential}}, nil
|
||||
}
|
||||
|
||||
_, err = web.ValidateDiscoverableLogin(userByHandle, *sessionData.SessionData, parsedResponse)
|
||||
if err != nil {
|
||||
slog.Warn("WebAuthn: ValidateDiscoverableLogin failed", slog.Any("error", err))
|
||||
json.Unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
|
@ -275,7 +311,7 @@ func (h *handler) finishLogin(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
h.store.WebAuthnSaveLogin(cred.Handle)
|
||||
h.store.WebAuthnSaveLogin(matchingCredential.Handle)
|
||||
|
||||
slog.Info("User authenticated successfully with webauthn",
|
||||
slog.Bool("authentication_successful", true),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue