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  }