Skip to content

Commit

Permalink
Allow the user to force unsafe password in immuadmin
Browse files Browse the repository at this point in the history
Signed-off-by: Stefano Scafiti <stefano.scafiti96@gmail.com>
  • Loading branch information
ostafen committed Apr 19, 2024
1 parent cb48e61 commit 8721fc8
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 32 deletions.
3 changes: 2 additions & 1 deletion cmd/helper/terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package helper

import (
"fmt"
"golang.org/x/crypto/ssh/terminal"
"io"
"io/ioutil"
"os"
"strings"

"golang.org/x/crypto/ssh/terminal"
)

type terminalReader struct {
Expand Down
3 changes: 3 additions & 0 deletions cmd/immuadmin/command/commandline.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package immuadmin
import (
"context"
"fmt"
"os"

"github.com/codenotary/immudb/pkg/client/homedir"
"github.com/codenotary/immudb/pkg/client/tokenservice"
Expand Down Expand Up @@ -55,6 +56,7 @@ type commandline struct {
config c.Config
immuClient client.ImmuClient
passwordReader c.PasswordReader
terminalReader c.TerminalReader
context context.Context
ts tokenservice.TokenService
onError func(msg interface{})
Expand All @@ -65,6 +67,7 @@ func NewCommandLine() *commandline {
cl := &commandline{}
cl.config.Name = "immuadmin"
cl.passwordReader = c.DefaultPasswordReader
cl.terminalReader = c.NewTerminalReader(os.Stdin)
cl.context = context.Background()
//
return cl
Expand Down
4 changes: 2 additions & 2 deletions cmd/immuadmin/command/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (cl *commandline) login(cmd *cobra.Command) {
if string(responseWarning) == auth.WarnDefaultAdminPassword {
c.PrintfColorW(cmd.OutOrStdout(), c.Yellow, "SECURITY WARNING: %s\n", responseWarning)

changedPassMsg, newPass, err := cl.changeUserPassword(userStr, pass)
changedPassMsg, newPass, err := cl.changeUserPassword(cmd, userStr, pass)
if err != nil {
cl.quit(err)
return err
Expand All @@ -70,7 +70,7 @@ func (cl *commandline) login(cmd *cobra.Command) {
return err
}

fmt.Fprint(cmd.OutOrStdout(), changedPassMsg)
fmt.Fprintln(cmd.OutOrStdout(), changedPassMsg)
}

return nil
Expand Down
43 changes: 33 additions & 10 deletions cmd/immuadmin/command/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import (
"github.com/spf13/cobra"
)

const unsecurePasswordMsg = "A strong password (containing upper and lower case letters, digits and symbols) would be advisable"

func (cl *commandline) user(cmd *cobra.Command) {
ccmd := &cobra.Command{
Use: "user command",
Expand Down Expand Up @@ -60,11 +62,11 @@ func (cl *commandline) user(cmd *cobra.Command) {
immuadmin user create user1 readwrite mydb
immuadmin user create user1 admin mydb`,
RunE: func(cmd *cobra.Command, args []string) error {
resp, err := cl.userCreate(args)
resp, err := cl.userCreate(cmd, args)
if err != nil {
c.QuitToStdErr(err)
}
fmt.Fprint(cmd.OutOrStdout(), resp)
fmt.Fprintln(cmd.OutOrStdout(), resp)
return nil
},
Args: cobra.RangeArgs(2, 3),
Expand All @@ -83,8 +85,8 @@ immuadmin user create user1 admin mydb`,
return fmt.Errorf("Error Reading Password")
}
}
if resp, _, err = cl.changeUserPassword(username, oldpass); err == nil {
fmt.Fprint(cmd.OutOrStdout(), resp)
if resp, _, err = cl.changeUserPassword(cmd, username, oldpass); err == nil {
fmt.Fprintln(cmd.OutOrStdout(), resp)
}
return err
},
Expand Down Expand Up @@ -135,14 +137,16 @@ immuadmin user create user1 admin mydb`,
cmd.AddCommand(ccmd)
}

func (cl *commandline) changeUserPassword(username string, oldpassword []byte) (string, []byte, error) {
func (cl *commandline) changeUserPassword(cmd *cobra.Command, username string, oldpassword []byte) (string, []byte, error) {
newpass, err := cl.passwordReader.Read(fmt.Sprintf("Choose a password for %s:", username))
if err != nil {
return "", nil, errors.New("Error Reading Password")
}
if err = auth.IsStrongPassword(string(newpass)); err != nil {
return "", nil, errors.New("password does not meet the requirements. It must contain upper and lower case letters, digits, punctuation mark or symbol")

if err := cl.checkPassword(cmd, string(newpass)); err != nil {
return "", nil, err
}

pass2, err := cl.passwordReader.Read("Confirm password:")
if err != nil {
return "", nil, errors.New("Error Reading Password")
Expand All @@ -156,6 +160,24 @@ func (cl *commandline) changeUserPassword(username string, oldpassword []byte) (
return fmt.Sprintf("%s's password has been changed", username), newpass, nil
}

func (cl *commandline) checkPassword(cmd *cobra.Command, newpass string) error {
if err := auth.IsStrongPassword(string(newpass)); err == nil {
return nil
}

c.PrintfColorW(cmd.OutOrStdout(), c.Yellow, "%s.\nDo you want to continue with your password instead? [Y/n]\n", unsecurePasswordMsg)

selected, err := cl.terminalReader.ReadFromTerminalYN("n")
if err != nil {
return err
}

if selected != "y" {
return errors.New("unable to change password")
}
return nil
}

func (cl *commandline) userList(args []string) (string, error) {
userlist, err := cl.immuClient.ListUsers(cl.context)
if err != nil {
Expand Down Expand Up @@ -231,7 +253,7 @@ func permissionToString(permission uint32) string {
}
}

func (cl *commandline) userCreate(args []string) (string, error) {
func (cl *commandline) userCreate(cmd *cobra.Command, args []string) (string, error) {
username := args[0]
permissionStr := args[1]
var databasename string
Expand Down Expand Up @@ -265,8 +287,9 @@ func (cl *commandline) userCreate(args []string) (string, error) {
if err != nil {
return "", fmt.Errorf("Error Reading Password")
}
if err = auth.IsStrongPassword(string(pass)); err != nil {
return "", fmt.Errorf("Password does not meet the requirements. It must contain upper and lower case letters, digits, punctuation mark or symbol")

if err := cl.checkPassword(cmd, string(pass)); err != nil {
return "", err
}
pass2, err := cl.passwordReader.Read("Confirm password:")
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ func (s *ImmuServer) loadSystemDatabase(
if !s.sysDB.IsReplica() {
s.sysDB.SetSyncReplication(false)

adminUsername, _, err := s.insertNewUser(context.Background(), []byte(auth.SysAdminUsername), []byte(adminPassword), auth.PermissionSysAdmin, "*", false, "")
adminUsername, _, err := s.insertNewUser(context.Background(), []byte(auth.SysAdminUsername), []byte(adminPassword), auth.PermissionSysAdmin, "*", "")
if err != nil {
return logErr(s.Logger, "%v", err)
}
Expand Down
6 changes: 2 additions & 4 deletions pkg/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1385,17 +1385,15 @@ func TestServerErrors(t *testing.T) {
adminCtx = metadata.NewIncomingContext(context.Background(), md)

// insertNewUser errors
_, _, err = s.insertNewUser(context.Background(), []byte("%"), nil, 1, DefaultDBName, true, auth.SysAdminUsername)
_, _, err = s.insertNewUser(context.Background(), []byte("%"), nil, 1, DefaultDBName, auth.SysAdminUsername)
require.ErrorContains(t, err, "username can only contain letters, digits and underscores")

username := "someusername"
usernameBytes := []byte(username)
password := "$omePassword1"
passwordBytes := []byte(password)
_, _, err = s.insertNewUser(context.Background(), usernameBytes, []byte("a"), 1, DefaultDBName, true, auth.SysAdminUsername)
require.ErrorContains(t, err, auth.PasswordRequirementsMsg)

_, _, err = s.insertNewUser(context.Background(), usernameBytes, passwordBytes, 99, DefaultDBName, false, auth.SysAdminUsername)
_, _, err = s.insertNewUser(context.Background(), usernameBytes, passwordBytes, 99, DefaultDBName, auth.SysAdminUsername)
require.ErrorContains(t, err, "unknown permission")

// getLoggedInUserDataFromUsername errors
Expand Down
20 changes: 6 additions & 14 deletions pkg/server/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (s *ImmuServer) CreateUser(ctx context.Context, r *schema.CreateUserRequest
return nil, fmt.Errorf("user already exists")
}

_, _, err = s.insertNewUser(ctx, r.User, r.Password, r.GetPermission(), r.Database, true, loggedInuser.Username)
_, _, err = s.insertNewUser(ctx, r.User, r.Password, r.GetPermission(), r.Database, loggedInuser.Username)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -519,19 +519,11 @@ func (s *ImmuServer) SetActiveUser(ctx context.Context, r *schema.SetActiveUserR
// insertNewUser inserts a new user to the system database and returns username and plain text password
// A new password is generated automatically if passed parameter is empty
// If enforceStrongAuth is true it checks if username and password meet security criteria
func (s *ImmuServer) insertNewUser(ctx context.Context, username []byte, plainPassword []byte, permission uint32, database string, enforceStrongAuth bool, createdBy string) ([]byte, []byte, error) {
if enforceStrongAuth {
if !auth.IsValidUsername(string(username)) {
return nil, nil, status.Errorf(
codes.InvalidArgument,
"username can only contain letters, digits and underscores")
}
}

if enforceStrongAuth {
if err := auth.IsStrongPassword(string(plainPassword)); err != nil {
return nil, nil, status.Errorf(codes.InvalidArgument, "%v", err)
}
func (s *ImmuServer) insertNewUser(ctx context.Context, username []byte, plainPassword []byte, permission uint32, database string, createdBy string) ([]byte, []byte, error) {
if !auth.IsValidUsername(string(username)) {
return nil, nil, status.Errorf(
codes.InvalidArgument,
"username can only contain letters, digits and underscores")
}

userdata := new(auth.User)
Expand Down

0 comments on commit 8721fc8

Please sign in to comment.