// Check that verify password works ok: it return true only if the following requiremnts are OK: // The password is equal to the current password and the password is not expired func Test_VerifyPwd(t *testing.T) { uPwd, err := NewUserPwd(defaultPassword, defaultSaltStr, true) if err != nil { t.Error("Test fail, can't initialized user password structure, error:", err) t.FailNow() } tPwd, _ := salt.GenerateSaltedPassword(defaultPassword, MinPasswordLength, MaxPasswordLength, uPwd.Salt, -1) pwd := GetHashedPwd(tPwd) err = uPwd.IsPasswordMatch(pwd) if err != nil { t.Errorf("Test fail: password '%v' was not accepted but it is the same as the current password, %v, error: %v", pwd, uPwd, err) } tPwd, _ = salt.GenerateSaltedPassword([]byte(string(pwd)+"a"), MinPasswordLength, MaxPasswordLength, uPwd.Salt, -1) wrongPwd := GetHashedPwd(tPwd) err = uPwd.IsPasswordMatch(wrongPwd) if err == nil { t.Errorf("Test fail: password '%v' was approved but it is different from the current password, %v", wrongPwd, uPwd) } for i := -2; i < 3; i++ { if i == 0 { continue } uPwd.Expiration = time.Now().Add(time.Duration(i) * time.Second) err = uPwd.IsPasswordMatch(pwd) if err == nil && i <= 0 { t.Errorf("Test fail: password was approved but it is not valid (expired, time now %v), %v", time.Now(), uPwd.Expiration) } else if err != nil && i > 0 { t.Errorf("Test fail: password was not approved but it valid (time now %v), %v", time.Now(), uPwd.Expiration) } } }
func (l AmRestful) restUpdatePwd(request *restful.Request, response *restful.Response) { var secrets cr.UpdateSecret err := request.ReadEntity(&secrets) if err != nil { l.setError(response, http.StatusBadRequest, err) return } userName := request.PathParameter(userIDParam) data := l.getAM(request, response, userName) if data == nil { return } tPwd, err := salt.GenerateSaltedPassword([]byte(secrets.OldPassword), password.MinPasswordLength, password.MaxPasswordLength, data.Pwd.Salt, -1) oldPwd := password.GetHashedPwd(tPwd) err = data.UpdateUserPwd(userName, oldPwd, []byte(secrets.NewPassword), false) if err != nil { l.setError(response, http.StatusBadRequest, err) return } // each time the password is updated, the token is extanded tokenStr, err := app.GenerateToken(userName, data.Privilege, false, getIPAddress(request), l.st.SignKey) if err != nil { l.setError(response, http.StatusInternalServerError, err) return } addLoginCookie(response, tokenStr) response.WriteHeaderAndEntity(http.StatusCreated, l.getURLPath(request, userName)) }
// Update the password, it's expioration time and it's state (is it a one-time-password or a regular one) func (u *UserPwd) updatePasswordHandler(currentPwd []byte, pwd []byte, expiration time.Time, temporaryPwd bool, checkPwdStrength bool) ([]byte, error) { pLock.Lock() defer pLock.Unlock() err := isPwdLengthValid(pwd) if err != nil { return nil, err } err = CheckPasswordStrength(string(pwd)) if err != nil && checkPwdStrength { return nil, err } err = u.isPasswordMatchHandler(currentPwd, true) if err != nil { return nil, err } tmpPwd, err := salt.GenerateSaltedPassword(pwd, MinPasswordLength, MaxPasswordLength, u.Salt, -1) if err != nil { return nil, fmt.Errorf("There was a problem while generating the new password: %v", err) } err = u.IsNewPwdValid(tmpPwd, false) if err != nil { return nil, err } newPwd := GetHashedPwd(tmpPwd) copy(u.OldPasswords[1:], u.OldPasswords[:]) u.OldPasswords[0] = u.Password u.Password = newPwd u.Expiration = expiration u.ErrorsCounter = 0 u.SetTemporaryPwd(temporaryPwd) return newPwd, nil }
func (p PwdRestful) restUpdatePassword(request *restful.Request, response *restful.Response) { var secrets cr.UpdateSecret name := request.PathParameter(userIDParam) err := request.ReadEntity(&secrets) if err != nil { p.setError(response, http.StatusBadRequest, err) return } data := p.getPwdData(request, response) if data == nil { return } tPwd, _ := salt.GenerateSaltedPassword([]byte(secrets.OldPassword), password.MinPasswordLength, password.MaxPasswordLength, p.saltStr, -1) pass := password.GetHashedPwd(tPwd) if err != nil { p.setError(response, http.StatusBadRequest, err) return } _, err = data.UpdatePassword(pass, []byte(secrets.NewPassword), checkPasswordStrength) if err != nil { p.setError(response, http.StatusBadRequest, err) return } response.WriteHeaderAndEntity(http.StatusCreated, p.getURLPath(request, name)) }
// This example shows how to generate a saltetd password from a given password and default salt func ExampleGenerateSaltedPassword() { pass := "******" res, err := salt.GenerateSaltedPassword([]byte(pass), minSecretLen, maxSecretLen, BasicSalt, -1) if err != nil { fmt.Println("GenerateSaltedPassword failed, error:", err) } else { fmt.Printf("* Generate basic salted password from a given password: '******', using the default parameters (sha1, show full password, 1 iteration and random salt: %v) is: %v", pass, BasicSalt, res) } }
// IsPasswordMatchHandler : use IsPasswordMatch with throttling parameters other than the default ones, for testing purposes func (u *AmUserInfo) IsPasswordMatchHandler(pwd []byte, throttleMiliSec int64, randomThrottleMiliSec int64) error { saltedPwd, _ := salt.GenerateSaltedPassword([]byte(pwd), password.MinPasswordLength, password.MaxPasswordLength, u.Pwd.Salt, -1) tPwd := password.GetHashedPwd(saltedPwd) err := u.Pwd.IsPasswordMatch(tPwd) // on error throttle for 1 second, reset the error counter if err != nil { PasswordErrorThrotling(throttleMiliSec, randomThrottleMiliSec) // u.Pwd.ErrorsCounter = 0 // the throttling is enougth return err } return nil }
// Generate a new secure storage minimal file that includes the root user with // basic Account Management: the root user privilege and password func createBasicFile(stFilePath string, name string, pass string, key []byte) { saltStr, _ := salt.GetRandomSalt(saltLen) _, err := salt.GenerateSaltedPassword([]byte(pass), password.MinPasswordLength, password.MaxPasswordLength, saltStr, -1) if err != nil { log.Fatalf("Error: can't generate salted password for '%v' user, error: %v", name, err) } ul := en.New() ul.AddUser(name) amUser, _ := am.NewUserAm(am.SuperUserPermission, []byte(pass), saltStr, true) ul.AddPropertyToEntity(name, defs.AmPropertyName, amUser) ul.StoreInfo(stFilePath, key, false) }
// Verify that the password is OK, after reset password, the old password // it not OK, the new temporary password is OK only once // and after password update, the new password is valid func Test_ResetPassword(t *testing.T) { user, _ := NewUserPwd(defaultPassword, defaultSaltStr, true) tPwd, _ := salt.GenerateSaltedPassword(defaultPassword, MinPasswordLength, MaxPasswordLength, user.Salt, -1) pass := GetHashedPwd(tPwd) err := user.IsPasswordMatch(pass) if err != nil { t.Errorf("Test fail: correct password: '******', return an error: %v", pass, err) } tmpPwd, err := user.ResetPassword() if err != nil { t.Errorf("Test fail: Reset password fail, error: %v", err) } tPwd, _ = salt.GenerateSaltedPassword(tmpPwd, MinPasswordLength, MaxPasswordLength, user.Salt, -1) newPwd := GetHashedPwd(tPwd) err = user.IsPasswordMatch(pass) if err == nil { t.Errorf("Test fail: Old password: '******' accepted", pass) } err = user.IsPasswordMatch(newPwd) if err != nil { t.Errorf("Test fail: The new automatic generated password: '******' was not accepted, error: %v", newPwd, err) } err = user.IsPasswordMatch(pass) if err == nil { t.Errorf("Test fail: The temporary pwd: '%v' accepted twice", newPwd) } for i := 0; i < 3; i++ { pass = []byte(string(pass) + "a1^A") expiration := time.Now().Add(time.Duration(defaultTemporaryPwdExpirationMinutes) * time.Second * 60) newPwd, err := user.UpdatePasswordAfterReset(user.Password, pass, expiration) if err != nil { t.Errorf("Test fail: can't use the new password: '******' (%v), return an error: %v", pass, string(pass), err) } else { err := user.IsPasswordMatch(newPwd) if err != nil { t.Errorf("Test fail: correct password: '******' (%v), return an error: %v", newPwd, string(pass), err) } } } }
// NewUserPwd : Generate a new UserPwd for a given password // The generated password is with a default expiration time func NewUserPwd(pwd []byte, saltData []byte, checkPwdStrength bool) (*UserPwd, error) { err := isPwdLengthValid(pwd) if err != nil { return nil, err } err = CheckPasswordStrength(string(pwd)) if err != nil && checkPwdStrength { return nil, err } newPwd, err := salt.GenerateSaltedPassword(pwd, MinPasswordLength, MaxPasswordLength, saltData, -1) if err != nil { return nil, err } setPwd := GetHashedPwd(newPwd) return &UserPwd{setPwd, saltData, getNewDefaultPasswordExpirationTime(), 0, defaultTemporaryPwd, [defaultNumberOfOldPasswords][]byte{}}, nil }
// Check that temporary password can be used exctly once func Test_UseOfTemporaryPwd(t *testing.T) { user, err := NewUserPwd(defaultPassword, defaultSaltStr, true) if err != nil { t.Error("Test fail, can't initialized user password structure, error:", err) t.FailNow() } tPwd, _ := salt.GenerateSaltedPassword(defaultPassword, MinPasswordLength, MaxPasswordLength, user.Salt, -1) pwd := GetHashedPwd(tPwd) user.SetTemporaryPwd(true) err = user.IsPasswordMatch(pwd) if err != nil { t.Errorf("Test fail: password '%v' was not accepted but it is the same as the current password, %v, current time: %v, error: %v", pwd, user, time.Now(), err) } err = user.IsPasswordMatch(pwd) if err == nil { t.Errorf("Test fail: password '%v' accepted but it was a temporary password, and it was already used, %v, current time: %v", pwd, user, time.Now()) } }
// Example of how to use the reset password function: // This function resets the current password, // selects a new password with short expiration time // and lets the user use it exactly once func ExampleUserPwd_ResetPassword() { id := "User1" pwd := []byte("a1b2C@3d4") saltStr, _ := salt.GetRandomSalt(10) userPwd, _ := password.NewUserPwd(pwd, saltStr, false) tmpPwd, _ := userPwd.ResetPassword() tPwd, _ := salt.GenerateSaltedPassword(tmpPwd, 1, 100, saltStr, -1) newPwd := password.GetHashedPwd(tPwd) err := userPwd.IsPasswordMatch(newPwd) if err != nil { fmt.Printf("Check of newly generated password '%v' for user %v failed, error %v\n", newPwd, id, err) } else { fmt.Printf("Entity %v, after resetting password '%v' verified successfully\n", id, newPwd) } err = userPwd.IsPasswordMatch(newPwd) if err == nil { fmt.Printf("Error: Newly generated password '%v' could be used only once\n", newPwd) } else { fmt.Printf("Newly generated password '%v', for entity %v, can only be used once\n", newPwd, id) } }
// Example of how to use the password. // 1. Create a new password. // 2. Verify that the initial password is set correctly // 3. Change the user's password // 4. Verify that the old password is not valid anymore // 5. Verify that the new password is valid // 6. Verify that the old password can't be used any more // (at least not as long as it remains in the old passwords list) func ExampleUserPwd() { id := "User-1" pwd := []byte("a1B2c3d^@") saltStr, _ := salt.GetRandomSalt(8) userPwd, _ := password.NewUserPwd(pwd, saltStr, true) tPwd, _ := salt.GenerateSaltedPassword(pwd, minPasswordLength, maxPasswordLength, saltStr, -1) newPwd := password.GetHashedPwd(tPwd) err := userPwd.IsPasswordMatch(newPwd) if err != nil { fmt.Println("Error", err) } userNewPwd := []byte(string(pwd) + "a") newPwd, err = userPwd.UpdatePassword(userPwd.Password, userNewPwd, true) if err != nil { fmt.Printf("Password update for user %v to new password '%v' (%v) failed, error %v\n", id, newPwd, string(userNewPwd), err) } else { fmt.Printf("User '%v', updated password to '%v' (%v)\n", id, newPwd, string(userNewPwd)) } err = userPwd.IsPasswordMatch(newPwd) if err != nil { fmt.Printf("Check of the new password, '%v' (%v), for user %v failed, error %v\n", newPwd, string(userNewPwd), id, err) } else { fmt.Printf("User '%v', new password '%v' (%v) verified successfully\n", id, newPwd, string(userNewPwd)) } err = userPwd.IsPasswordMatch(pwd) if err == nil { fmt.Printf("Error: Old password '%v' (%v) for user %v accepted\n", pwd, string(pwd), id) } else { fmt.Printf("User '%v', Note that the old password '%v' (%v) cannot be used anymore\n", id, pwd, string(pwd)) } newPwd, err = userPwd.UpdatePassword(userPwd.Password, pwd, true) if err == nil { fmt.Printf("Error: Password '%v' (typed password %v) for user %v was already used\n", newPwd, string(pwd), id) } else { fmt.Printf("Entity '%v'. Note that the old password (entered password) %v was already used\n", id, string(pwd)) } }
func (p PwdRestful) restVerifyPassword(request *restful.Request, response *restful.Response) { var secret secretData err := request.ReadEntity(&secret) tPwd, _ := salt.GenerateSaltedPassword([]byte(secret.Password), password.MinPasswordLength, password.MaxPasswordLength, p.saltStr, -1) pass := password.GetHashedPwd(tPwd) if err != nil { p.setError(response, http.StatusBadRequest, err) return } data := p.getPwdData(request, response) if data == nil { return } err = data.IsPasswordMatch(pass) ok := true if err != nil { ok = false } res := cr.Match{Match: ok, Message: cr.NoMessageStr} if ok == false && err != nil { res.Message = fmt.Sprintf("%v", err) } response.WriteHeaderAndEntity(http.StatusOK, res) }
func getSaltedPass(secret, saltData []byte) []byte { pass, _ := salt.GenerateSaltedPassword(secret, minSecretLen, maxSecretLen, saltData, SecretLen) return bytes.Replace(pass, []byte{'0'}, []byte{'a'}, -1) }