예제 #1
0
파일: account.go 프로젝트: logan/heim
func (m *accountManager) GetPasswordResetAccount(ctx scope.Context, confirmation string) (proto.Account, error) {
	id, mac, err := proto.ParsePasswordResetConfirmation(confirmation)
	if err != nil {
		return nil, err
	}

	req, ok := m.b.resetReqs[id]
	if !ok {
		return nil, proto.ErrInvalidConfirmationCode
	}

	if !req.VerifyMAC(mac) {
		return nil, proto.ErrInvalidConfirmationCode
	}

	if req.Expires.Before(time.Now()) {
		return nil, proto.ErrInvalidConfirmationCode
	}

	account, ok := m.b.accounts[req.AccountID]
	if !ok {
		return nil, proto.ErrInvalidConfirmationCode
	}

	return account, nil
}
예제 #2
0
파일: account.go 프로젝트: logan/heim
func (b *AccountManagerBinding) resolvePasswordReset(
	db gorp.SqlExecutor, confirmation string) (*proto.PasswordResetRequest, *AccountBinding, error) {
	id, mac, err := proto.ParsePasswordResetConfirmation(confirmation)
	if err != nil {
		return nil, nil, err
	}

	req := &proto.PasswordResetRequest{
		ID: id,
	}

	var (
		stored  PasswordResetRequest
		account *AccountBinding
	)

	cols, err := allColumns(b.DbMap, PasswordResetRequest{}, "")
	if err != nil {
		return nil, nil, err
	}
	err = db.SelectOne(
		&stored,
		fmt.Sprintf(
			"SELECT %s FROM password_reset_request WHERE id = $1 AND expires > NOW() AND invalidated IS NULL AND consumed IS NULL",
			cols),
		id.String())
	if err != nil && err != sql.ErrNoRows {
		return nil, nil, err
	}
	if err == nil {
		req.Key = stored.Key
		if err := req.AccountID.FromString(stored.AccountID); err == nil {
			account, err = b.get(db, req.AccountID)
			if err != nil && err != proto.ErrAccountNotFound {
				return nil, nil, err
			}
		}
	}

	if !req.VerifyMAC(mac) || account == nil {
		fmt.Printf("invalid mac or no account (%#v)\n", account)
		return nil, nil, proto.ErrInvalidConfirmationCode
	}

	return req, account, nil
}
예제 #3
0
파일: account.go 프로젝트: rmasoni/heim
func (m *accountManager) ConfirmPasswordReset(
	ctx scope.Context, kms security.KMS, confirmation, password string) error {

	m.b.Lock()
	defer m.b.Unlock()

	id, mac, err := proto.ParsePasswordResetConfirmation(confirmation)
	if err != nil {
		return err
	}

	req, ok := m.b.resetReqs[id]
	if !ok {
		return proto.ErrInvalidConfirmationCode
	}

	if !req.VerifyMAC(mac) {
		return proto.ErrInvalidConfirmationCode
	}

	if req.Expires.Before(time.Now()) {
		return proto.ErrInvalidConfirmationCode
	}

	account, ok := m.b.accounts[req.AccountID]
	if !ok {
		return proto.ErrInvalidConfirmationCode
	}

	sec, err := account.(*memAccount).sec.ResetPassword(kms, password)
	if err != nil {
		return err
	}

	account.(*memAccount).sec = *sec
	for id, req := range m.b.resetReqs {
		if req.AccountID == account.ID() {
			delete(m.b.resetReqs, id)
		}
	}

	return nil
}
예제 #4
0
파일: account.go 프로젝트: NotAMoose/heim
func (b *AccountManagerBinding) ConfirmPasswordReset(
	ctx scope.Context, kms security.KMS, confirmation, password string) error {

	id, mac, err := proto.ParsePasswordResetConfirmation(confirmation)
	if err != nil {
		return err
	}

	t, err := b.DbMap.Begin()
	if err != nil {
		return err
	}

	rollback := func() {
		if err := t.Rollback(); err != nil {
			backend.Logger(ctx).Printf("rollback error: %s", err)
		}
	}

	req := &proto.PasswordResetRequest{
		ID: id,
	}

	var (
		stored  PasswordResetRequest
		account *AccountBinding
	)

	cols, err := allColumns(b.DbMap, PasswordResetRequest{}, "")
	if err != nil {
		return err
	}
	err = t.SelectOne(
		&stored,
		fmt.Sprintf(
			"SELECT %s FROM password_reset_request WHERE id = $1 AND expires > NOW() AND invalidated IS NULL AND consumed IS NULL",
			cols),
		id.String())
	if err != nil && err != sql.ErrNoRows {
		rollback()
		return err
	}

	if err == nil {
		req.Key = stored.Key
		if err := req.AccountID.FromString(stored.AccountID); err == nil {
			account, err = b.get(t, req.AccountID)
			if err != nil && err != proto.ErrAccountNotFound {
				rollback()
				return err
			}
		}
	}

	if !req.VerifyMAC(mac) || account == nil {
		rollback()
		fmt.Printf("invalid mac or no account (%#v)\n", account)
		return proto.ErrInvalidConfirmationCode
	}

	sec, err := account.accountSecurity().ResetPassword(kms, password)
	if err != nil {
		rollback()
		fmt.Printf("reset password failed: %s\n", err)
		return err
	}

	_, err = t.Exec(
		"UPDATE account SET mac = $2, encrypted_user_key = $3 WHERE id = $1",
		account.ID().String(), sec.MAC, sec.UserKey.Ciphertext)
	if err != nil {
		rollback()
		fmt.Printf("update 1 failed: %s\n", err)
		return err
	}

	_, err = t.Exec("UPDATE password_reset_request SET consumed = NOW() where id = $1", id.String())
	if err != nil {
		rollback()
		fmt.Printf("update 2 failed: %s\n", err)
		return err
	}

	_, err = t.Exec(
		"UPDATE password_reset_request SET invalidated = NOW() where account_id = $1 AND id != $2",
		account.ID().String(), id)
	if err != nil {
		rollback()
		fmt.Printf("update 3 failed: %s\n", err)
		return err
	}

	if err := t.Commit(); err != nil {
		fmt.Printf("commit failed: %s\n", err)
		return err
	}

	return nil
}