github.com/jxgolibs/go-oauth2-server@v1.0.1/oauth/user.go (about) 1 package oauth 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 "time" 8 9 "github.com/RichardKnop/go-oauth2-server/models" 10 "github.com/RichardKnop/go-oauth2-server/util" 11 pass "github.com/RichardKnop/go-oauth2-server/util/password" 12 "github.com/RichardKnop/uuid" 13 "github.com/jinzhu/gorm" 14 ) 15 16 var ( 17 // MinPasswordLength defines minimum password length 18 MinPasswordLength = 6 19 20 // ErrPasswordTooShort ... 21 ErrPasswordTooShort = fmt.Errorf( 22 "Password must be at least %d characters long", 23 MinPasswordLength, 24 ) 25 // ErrUserNotFound ... 26 ErrUserNotFound = errors.New("User not found") 27 // ErrInvalidUserPassword ... 28 ErrInvalidUserPassword = errors.New("Invalid user password") 29 // ErrCannotSetEmptyUsername ... 30 ErrCannotSetEmptyUsername = errors.New("Cannot set empty username") 31 // ErrUserPasswordNotSet ... 32 ErrUserPasswordNotSet = errors.New("User password not set") 33 // ErrUsernameTaken ... 34 ErrUsernameTaken = errors.New("Username taken") 35 ) 36 37 // UserExists returns true if user exists 38 func (s *Service) UserExists(username string) bool { 39 _, err := s.FindUserByUsername(username) 40 return err == nil 41 } 42 43 // FindUserByUsername looks up a user by username 44 func (s *Service) FindUserByUsername(username string) (*models.OauthUser, error) { 45 // Usernames are case insensitive 46 user := new(models.OauthUser) 47 notFound := s.db.Where("username = LOWER(?)", username). 48 First(user).RecordNotFound() 49 50 // Not found 51 if notFound { 52 return nil, ErrUserNotFound 53 } 54 55 return user, nil 56 } 57 58 // CreateUser saves a new user to database 59 func (s *Service) CreateUser(roleID, username, password string) (*models.OauthUser, error) { 60 return s.createUserCommon(s.db, roleID, username, password) 61 } 62 63 // CreateUserTx saves a new user to database using injected db object 64 func (s *Service) CreateUserTx(tx *gorm.DB, roleID, username, password string) (*models.OauthUser, error) { 65 return s.createUserCommon(tx, roleID, username, password) 66 } 67 68 // SetPassword sets a user password 69 func (s *Service) SetPassword(user *models.OauthUser, password string) error { 70 return s.setPasswordCommon(s.db, user, password) 71 } 72 73 // SetPasswordTx sets a user password in a transaction 74 func (s *Service) SetPasswordTx(tx *gorm.DB, user *models.OauthUser, password string) error { 75 return s.setPasswordCommon(tx, user, password) 76 } 77 78 // AuthUser authenticates user 79 func (s *Service) AuthUser(username, password string) (*models.OauthUser, error) { 80 // Fetch the user 81 user, err := s.FindUserByUsername(username) 82 if err != nil { 83 return nil, err 84 } 85 86 // Check that the password is set 87 if !user.Password.Valid { 88 return nil, ErrUserPasswordNotSet 89 } 90 91 // Verify the password 92 if pass.VerifyPassword(user.Password.String, password) != nil { 93 return nil, ErrInvalidUserPassword 94 } 95 96 return user, nil 97 } 98 99 // UpdateUsername ... 100 func (s *Service) UpdateUsername(user *models.OauthUser, username string) error { 101 if username == "" { 102 return ErrCannotSetEmptyUsername 103 } 104 105 return s.updateUsernameCommon(s.db, user, username) 106 } 107 108 // UpdateUsernameTx ... 109 func (s *Service) UpdateUsernameTx(tx *gorm.DB, user *models.OauthUser, username string) error { 110 return s.updateUsernameCommon(tx, user, username) 111 } 112 113 func (s *Service) createUserCommon(db *gorm.DB, roleID, username, password string) (*models.OauthUser, error) { 114 // Start with a user without a password 115 user := &models.OauthUser{ 116 MyGormModel: models.MyGormModel{ 117 ID: uuid.New(), 118 CreatedAt: time.Now().UTC(), 119 }, 120 RoleID: util.StringOrNull(roleID), 121 Username: strings.ToLower(username), 122 Password: util.StringOrNull(""), 123 } 124 125 // If the password is being set already, create a bcrypt hash 126 if password != "" { 127 if len(password) < MinPasswordLength { 128 return nil, ErrPasswordTooShort 129 } 130 passwordHash, err := pass.HashPassword(password) 131 if err != nil { 132 return nil, err 133 } 134 user.Password = util.StringOrNull(string(passwordHash)) 135 } 136 137 // Check the username is available 138 if s.UserExists(user.Username) { 139 return nil, ErrUsernameTaken 140 } 141 142 // Create the user 143 if err := db.Create(user).Error; err != nil { 144 return nil, err 145 } 146 return user, nil 147 } 148 149 func (s *Service) setPasswordCommon(db *gorm.DB, user *models.OauthUser, password string) error { 150 if len(password) < MinPasswordLength { 151 return ErrPasswordTooShort 152 } 153 154 // Create a bcrypt hash 155 passwordHash, err := pass.HashPassword(password) 156 if err != nil { 157 return err 158 } 159 160 // Set the password on the user object 161 return db.Model(user).UpdateColumns(models.OauthUser{ 162 Password: util.StringOrNull(string(passwordHash)), 163 MyGormModel: models.MyGormModel{UpdatedAt: time.Now().UTC()}, 164 }).Error 165 } 166 167 func (s *Service) updateUsernameCommon(db *gorm.DB, user *models.OauthUser, username string) error { 168 if username == "" { 169 return ErrCannotSetEmptyUsername 170 } 171 return db.Model(user).UpdateColumn("username", strings.ToLower(username)).Error 172 }