passkey existing

This commit is contained in:
2026-06-16 17:05:15 -04:00
parent 4655008154
commit b6d2ded141
9 changed files with 188 additions and 2 deletions

View File

@@ -190,6 +190,57 @@ func (s *Service) FinishPasskeyRegistration(ctx context.Context, challengeID str
return s.repo.GetUserByID(ctx, user.ID)
}
func (s *Service) BeginCurrentUserPasskeyRegistration(ctx context.Context, principal Principal) (any, string, error) {
if principal.UserID == "" {
return nil, "", fmt.Errorf("authentication required")
}
user, err := s.repo.GetUserByID(ctx, principal.UserID)
if err != nil {
return nil, "", err
}
if user.Disabled {
return nil, "", fmt.Errorf("account disabled")
}
creation, session, err := s.webauthn.BeginRegistration(user)
if err != nil {
return nil, "", err
}
challengeID, err := s.repo.SaveChallenge(ctx, user.ID, "webauthn_registration", *session, challengeTTL)
if err != nil {
return nil, "", err
}
return creation, challengeID, nil
}
func (s *Service) FinishCurrentUserPasskeyRegistration(ctx context.Context, principal Principal, challengeID string, r *http.Request) (User, error) {
if principal.UserID == "" {
return User{}, fmt.Errorf("authentication required")
}
session, userID, err := s.repo.ConsumeChallenge(ctx, challengeID, "webauthn_registration")
if err != nil {
return User{}, err
}
if userID != principal.UserID {
return User{}, fmt.Errorf("challenge does not belong to the current user")
}
user, err := s.repo.GetUserByID(ctx, userID)
if err != nil {
return User{}, err
}
if user.Disabled {
return User{}, fmt.Errorf("account disabled")
}
credential, err := s.webauthn.FinishRegistration(user, session, r)
if err != nil {
return User{}, err
}
if err := s.repo.SaveCredential(ctx, user.ID, *credential); err != nil {
return User{}, err
}
s.repo.Audit(ctx, user.ID, "auth.passkey.add", "user", user.ID, clientIP(r), r.UserAgent(), nil)
return s.repo.GetUserByID(ctx, user.ID)
}
func (s *Service) BeginPasskeyLogin(ctx context.Context, email string) (any, string, error) {
user, err := s.repo.GetUserByEmail(ctx, normalizeEmail(email))
if err != nil {

View File

@@ -315,6 +315,21 @@ func TestPublicRegistrationCannotAttachCredentialsToExistingUser(t *testing.T) {
}
}
func TestCurrentUserCanBeginPasskeyRegistrationForExistingAccount(t *testing.T) {
service := setupAuthTestService(t)
ctx := context.Background()
user := setupInitialAdmin(t, service, false)
principal := principalFromUser(user, "session", "sess:test", "", nil, time.Now().Add(time.Hour))
options, challengeID, err := service.BeginCurrentUserPasskeyRegistration(ctx, principal)
if err != nil {
t.Fatalf("BeginCurrentUserPasskeyRegistration() error = %v", err)
}
if options == nil || challengeID == "" {
t.Fatalf("options = %#v, challengeID = %q; want registration options and challenge", options, challengeID)
}
}
func TestInitialSetupCanDisablePublicRegistration(t *testing.T) {
service := setupAuthTestService(t)
ctx := context.Background()