github.com/wanliu/go-oauth2-server@v0.0.0-20180817021415-f928fa1580df/oauth/user.go (about) 1 package oauth 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 "time" 8 9 "github.com/RichardKnop/uuid" 10 "github.com/jinzhu/gorm" 11 "github.com/wanliu/go-oauth2-server/models" 12 "github.com/wanliu/go-oauth2-server/util" 13 pass "github.com/wanliu/go-oauth2-server/util/password" 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 type Params map[string]interface{} 38 39 // UserExists returns true if user exists 40 func (s *Service) UserExists(username string) bool { 41 _, err := s.FindUserByUsername(username) 42 return err == nil 43 } 44 45 // FindUserByUsername looks up a user by username 46 func (s *Service) FindUserByUsername(username string) (*models.OauthUser, error) { 47 // Usernames are case insensitive 48 user := new(models.OauthUser) 49 notFound := s.db.Where("username = LOWER(?)", username). 50 First(user).RecordNotFound() 51 52 // Not found 53 if notFound { 54 return nil, ErrUserNotFound 55 } 56 57 return user, nil 58 } 59 60 // FindUserByID looks up a user by Id 61 func (s *Service) FindUserByID(id string) (*models.OauthUser, error) { 62 // Usernames are case insensitive 63 user := new(models.OauthUser) 64 notFound := s.db.Where("id = ?", id). 65 First(user).RecordNotFound() 66 67 // Not found 68 if notFound { 69 return nil, ErrUserNotFound 70 } 71 72 return user, nil 73 } 74 75 func (s *Service) GetUserByToken(tok string) (*models.OauthUser, error) { 76 var ( 77 token models.OauthAccessToken 78 user models.OauthUser 79 ) 80 81 if err := s.db.Model(&models.OauthAccessToken{}).Where("token = ?", tok).First(&token).Error; err != nil { 82 return nil, err 83 } 84 85 if err := s.db.Model(&models.OauthUser{}).Where("id = ?", token.UserID).First(&user).Error; err != nil { 86 return nil, err 87 } 88 return &user, nil 89 } 90 91 // CreateUser saves a new user to database 92 func (s *Service) CreateUser(roleID, username, password string) (*models.OauthUser, error) { 93 return s.createUserCommon(s.db, roleID, username, password) 94 } 95 96 // CreateUserTx saves a new user to database using injected db object 97 func (s *Service) CreateUserTx(tx *gorm.DB, roleID, username, password string) (*models.OauthUser, error) { 98 return s.createUserCommon(tx, roleID, username, password) 99 } 100 101 // SetPassword sets a user password 102 func (s *Service) SetPassword(user *models.OauthUser, password string) error { 103 return s.setPasswordCommon(s.db, user, password) 104 } 105 106 // SetPasswordTx sets a user password in a transaction 107 func (s *Service) SetPasswordTx(tx *gorm.DB, user *models.OauthUser, password string) error { 108 return s.setPasswordCommon(tx, user, password) 109 } 110 111 // AuthUser authenticates user 112 func (s *Service) AuthUser(username, password string) (*models.OauthUser, error) { 113 // Fetch the user 114 user, err := s.FindUserByUsername(username) 115 if err != nil { 116 return nil, err 117 } 118 119 // Check that the password is set 120 if !user.Password.Valid { 121 return nil, ErrUserPasswordNotSet 122 } 123 124 // Verify the password 125 if pass.VerifyPassword(user.Password.String, password) != nil { 126 return nil, ErrInvalidUserPassword 127 } 128 129 return user, nil 130 } 131 132 // UpdateUsername ... 133 func (s *Service) UpdateUsername(user *models.OauthUser, username string) error { 134 if username == "" { 135 return ErrCannotSetEmptyUsername 136 } 137 138 return s.updateUsernameCommon(s.db, user, username) 139 } 140 141 // UpdateUsernameTx ... 142 func (s *Service) UpdateUsernameTx(tx *gorm.DB, user *models.OauthUser, username string) error { 143 return s.updateUsernameCommon(tx, user, username) 144 } 145 146 func (s *Service) createUserCommon(db *gorm.DB, roleID, username, password string) (*models.OauthUser, error) { 147 // Start with a user without a password 148 user := &models.OauthUser{ 149 MyGormModel: models.MyGormModel{ 150 ID: uuid.New(), 151 CreatedAt: time.Now().UTC(), 152 }, 153 RoleID: util.StringOrNull(roleID), 154 Username: strings.ToLower(username), 155 Password: util.StringOrNull(""), 156 } 157 158 // If the password is being set already, create a bcrypt hash 159 if password != "" { 160 if len(password) < MinPasswordLength { 161 return nil, ErrPasswordTooShort 162 } 163 passwordHash, err := pass.HashPassword(password) 164 if err != nil { 165 return nil, err 166 } 167 user.Password = util.StringOrNull(string(passwordHash)) 168 } 169 170 // Check the username is available 171 if s.UserExists(user.Username) { 172 return nil, ErrUsernameTaken 173 } 174 175 // Create the user 176 if err := db.Create(user).Error; err != nil { 177 return nil, err 178 } 179 return user, nil 180 } 181 182 func (s *Service) setPasswordCommon(db *gorm.DB, user *models.OauthUser, password string) error { 183 if len(password) < MinPasswordLength { 184 return ErrPasswordTooShort 185 } 186 187 // Create a bcrypt hash 188 passwordHash, err := pass.HashPassword(password) 189 if err != nil { 190 return err 191 } 192 193 // Set the password on the user object 194 return db.Model(user).UpdateColumns(models.OauthUser{ 195 Password: util.StringOrNull(string(passwordHash)), 196 MyGormModel: models.MyGormModel{UpdatedAt: time.Now().UTC()}, 197 }).Error 198 } 199 200 func (s *Service) updateUsernameCommon(db *gorm.DB, user *models.OauthUser, username string) error { 201 if username == "" { 202 return ErrCannotSetEmptyUsername 203 } 204 return db.Model(user).UpdateColumn("username", strings.ToLower(username)).Error 205 } 206 207 func (s *Service) UpdateUser(user *models.OauthUser, params Params) error { 208 return s.db.Model(user).Updates(params).Error 209 }