Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: password update, password service transaction handling #1669

Merged
merged 3 commits into from
Oct 9, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (a PasswordLogin) Execute(c flowpilot.ExecutionContext) error {
return a.wrongCredentialsError(c)
}

err := deps.PasswordService.VerifyPassword(userID, c.Input().Get("password").String())
err := deps.PasswordService.VerifyPassword(deps.Tx, userID, c.Input().Get("password").String())
if err != nil {
if errors.Is(err, services.ErrorPasswordInvalid) {
err = deps.AuditLogger.CreateWithConnection(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (a PasswordRecovery) Execute(c flowpilot.ExecutionContext) error {

authUserID := c.Stash().Get(shared.StashPathUserID).String()

err := deps.PasswordService.RecoverPassword(uuid.FromStringOrNil(authUserID), newPassword)
err := deps.PasswordService.RecoverPassword(deps.Tx, uuid.FromStringOrNil(authUserID), newPassword)

if err != nil {
if errors.Is(err, services.ErrorPasswordInvalid) {
Expand Down
2 changes: 1 addition & 1 deletion backend/flow_api/flow/profile/action_password_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (a PasswordCreate) Execute(c flowpilot.ExecutionContext) error {

passwordCredential := models.NewPasswordCredential(userModel.ID, password) // ?

err := deps.PasswordService.CreatePassword(userModel.ID, password) // ?
err := deps.PasswordService.CreatePassword(deps.Tx, userModel.ID, password) // ?
if err != nil {
return fmt.Errorf("could not set password: %w", err)
}
Expand Down
6 changes: 1 addition & 5 deletions backend/flow_api/flow/profile/action_password_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ func (a PasswordUpdate) Execute(c flowpilot.ExecutionContext) error {

password := c.Input().Get("password").String()

passwordCredential := models.NewPasswordCredential(userModel.ID, password) // ?

err := deps.PasswordService.UpdatePassword(passwordCredential, password)
err := deps.PasswordService.UpdatePassword(deps.Tx, userModel.PasswordCredential, password)
if err != nil {
return fmt.Errorf("could not udate password: %w", err)
}
Expand All @@ -74,7 +72,5 @@ func (a PasswordUpdate) Execute(c flowpilot.ExecutionContext) error {
return fmt.Errorf("could not create audit log: %w", err)
}

userModel.PasswordCredential = passwordCredential

return c.Continue(shared.StateProfileInit)
}
33 changes: 18 additions & 15 deletions backend/flow_api/services/password.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,24 @@ package services
import (
"errors"
"fmt"
"github.com/gobuffalo/pop/v6"
"github.com/gofrs/uuid"
"github.com/teamhanko/hanko/backend/config"
"github.com/teamhanko/hanko/backend/persistence"
"github.com/teamhanko/hanko/backend/persistence/models"
"golang.org/x/crypto/bcrypt"
"time"
)

var (
ErrorPasswordInvalid = errors.New("password invalid")
)

type Password interface {
VerifyPassword(userId uuid.UUID, password string) error
RecoverPassword(userId uuid.UUID, newPassword string) error
CreatePassword(userId uuid.UUID, newPassword string) error
UpdatePassword(passwordCredentialModel *models.PasswordCredential, newPassword string) error
VerifyPassword(tx *pop.Connection, userId uuid.UUID, password string) error
RecoverPassword(tx *pop.Connection, userId uuid.UUID, newPassword string) error
CreatePassword(tx *pop.Connection, userId uuid.UUID, newPassword string) error
UpdatePassword(tx *pop.Connection, passwordCredentialModel *models.PasswordCredential, newPassword string) error
}

type password struct {
Expand All @@ -33,8 +35,8 @@ func NewPasswordService(cfg config.Config, persister persistence.Persister) Pass
}
}

func (s password) VerifyPassword(userId uuid.UUID, password string) error {
user, err := s.persister.GetUserPersister().Get(userId)
func (s password) VerifyPassword(tx *pop.Connection, userId uuid.UUID, password string) error {
user, err := s.persister.GetUserPersisterWithConnection(tx).Get(userId)
if err != nil {
return fmt.Errorf("failed to get user: %w", err)
}
Expand All @@ -43,7 +45,7 @@ func (s password) VerifyPassword(userId uuid.UUID, password string) error {
return ErrorPasswordInvalid
}

pw, err := s.persister.GetPasswordCredentialPersister().GetByUserID(userId)
pw, err := s.persister.GetPasswordCredentialPersisterWithConnection(tx).GetByUserID(userId)
if err != nil {
return fmt.Errorf("error retrieving password credential: %w", err)
}
Expand All @@ -59,18 +61,18 @@ func (s password) VerifyPassword(userId uuid.UUID, password string) error {
return nil
}

func (s password) RecoverPassword(userId uuid.UUID, newPassword string) error {
passwordPersister := s.persister.GetPasswordCredentialPersister()
func (s password) RecoverPassword(tx *pop.Connection, userId uuid.UUID, newPassword string) error {
passwordPersister := s.persister.GetPasswordCredentialPersisterWithConnection(tx)

passwordCredentialModel, err := passwordPersister.GetByUserID(userId)
if err != nil {
return fmt.Errorf("failed to get password credential by user id: %w", err)
}

if passwordCredentialModel == nil {
err = s.CreatePassword(userId, newPassword)
err = s.CreatePassword(tx, userId, newPassword)
} else {
err = s.UpdatePassword(passwordCredentialModel, newPassword)
err = s.UpdatePassword(tx, passwordCredentialModel, newPassword)
}

if err != nil {
Expand All @@ -80,31 +82,32 @@ func (s password) RecoverPassword(userId uuid.UUID, newPassword string) error {
return nil
}

func (s password) CreatePassword(userId uuid.UUID, newPassword string) error {
func (s password) CreatePassword(tx *pop.Connection, userId uuid.UUID, newPassword string) error {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), 12)
if err != nil {
return ErrorPasswordInvalid
}

passwordCredentialModel := models.NewPasswordCredential(userId, string(hashedPassword))

err = s.persister.GetPasswordCredentialPersister().Create(*passwordCredentialModel)
err = s.persister.GetPasswordCredentialPersisterWithConnection(tx).Create(*passwordCredentialModel)
if err != nil {
return fmt.Errorf("failed to set password: %w", err)
}

return nil
}

func (s password) UpdatePassword(passwordCredentialModel *models.PasswordCredential, newPassword string) error {
func (s password) UpdatePassword(tx *pop.Connection, passwordCredentialModel *models.PasswordCredential, newPassword string) error {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), 12)
if err != nil {
return ErrorPasswordInvalid
}

passwordCredentialModel.Password = string(hashedPassword)
passwordCredentialModel.UpdatedAt = time.Now().UTC()

err = s.persister.GetPasswordCredentialPersister().Update(*passwordCredentialModel)
err = s.persister.GetPasswordCredentialPersisterWithConnection(tx).Update(*passwordCredentialModel)
if err != nil {
return fmt.Errorf("failed to update password: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions backend/persistence/models/password_credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ func NewPasswordCredential(userId uuid.UUID, password string) *PasswordCredentia
ID: id,
UserId: userId,
Password: password,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
}

Expand Down
Loading