Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
290 lines
6.7 KiB
Go
290 lines
6.7 KiB
Go
package service
|
|
|
|
import (
|
|
"github.com/cortezaproject/corteza/server/system/types"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func Test_isValidPassword(t *testing.T) {
|
|
var (
|
|
pwdPlain = " ... plain password ... "
|
|
pwdHashedB, _ = bcrypt.GenerateFromPassword([]byte(pwdPlain), bcrypt.DefaultCost)
|
|
pwdHashed = string(pwdHashedB)
|
|
pwdUnknown = "$2a$10$8sOZxfZinxnu3bAtpkqEx.wBBwOfci6aG1szgUyxm5.BL2WiLu.ni"
|
|
)
|
|
|
|
cases := []struct {
|
|
name string
|
|
password string
|
|
cc types.CredentialSet
|
|
rval bool
|
|
}{
|
|
{
|
|
name: "empty set",
|
|
rval: false,
|
|
},
|
|
{
|
|
name: "bad pwd",
|
|
rval: false,
|
|
password: " foo ",
|
|
cc: types.CredentialSet{&types.Credential{ID: 1, Credentials: pwdHashed}},
|
|
},
|
|
{
|
|
name: "invalid credentials",
|
|
rval: false,
|
|
password: " foo ",
|
|
cc: types.CredentialSet{&types.Credential{ID: 0, Credentials: pwdHashed}},
|
|
},
|
|
{
|
|
name: "ok",
|
|
rval: true,
|
|
password: pwdPlain,
|
|
cc: types.CredentialSet{&types.Credential{ID: 1, Credentials: pwdHashed}},
|
|
},
|
|
{
|
|
name: "multipass",
|
|
rval: true,
|
|
password: pwdPlain,
|
|
cc: types.CredentialSet{
|
|
&types.Credential{ID: 0, Credentials: pwdHashed},
|
|
&types.Credential{ID: 1, Credentials: pwdUnknown},
|
|
&types.Credential{ID: 2, Credentials: pwdHashed},
|
|
&types.Credential{ID: 3, Credentials: ""},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
rsp = findValidPassword(c.cc, c.password)
|
|
)
|
|
|
|
if c.rval {
|
|
req.NotNil(rsp)
|
|
} else {
|
|
req.Nil(rsp)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_isPasswordReused(t *testing.T) {
|
|
var (
|
|
pwdPlain = " ... plain password ... "
|
|
pwdHashedB, _ = bcrypt.GenerateFromPassword([]byte(pwdPlain), bcrypt.DefaultCost)
|
|
pwdHashed = string(pwdHashedB)
|
|
pwdUnknown = "$2a$10$8sOZxfZinxnu3bAtpkqEx.wBBwOfci6aG1szgUyxm5.BL2WiLu.ni"
|
|
)
|
|
|
|
cases := []struct {
|
|
name string
|
|
password string
|
|
window time.Duration
|
|
cc types.CredentialSet
|
|
rval bool
|
|
}{
|
|
{
|
|
name: "no credentials, not reused",
|
|
rval: false,
|
|
password: pwdPlain,
|
|
cc: types.CredentialSet{},
|
|
},
|
|
{
|
|
name: "not reused",
|
|
rval: false,
|
|
password: pwdPlain,
|
|
cc: types.CredentialSet{
|
|
&types.Credential{ID: 1, Credentials: pwdUnknown},
|
|
&types.Credential{ID: 2, Credentials: ""},
|
|
},
|
|
},
|
|
{
|
|
name: "present, valid, first",
|
|
rval: true,
|
|
password: pwdPlain,
|
|
cc: types.CredentialSet{
|
|
&types.Credential{ID: 1, Credentials: pwdHashed},
|
|
&types.Credential{ID: 2, Credentials: pwdUnknown},
|
|
&types.Credential{ID: 3, Credentials: ""},
|
|
},
|
|
},
|
|
{
|
|
name: "present, but within time window",
|
|
rval: false,
|
|
password: pwdPlain,
|
|
window: 5 * time.Minute,
|
|
cc: types.CredentialSet{
|
|
&types.Credential{ID: 1, Credentials: pwdHashed, CreatedAt: *now()},
|
|
&types.Credential{ID: 2, Credentials: pwdUnknown},
|
|
&types.Credential{ID: 3, Credentials: ""},
|
|
},
|
|
},
|
|
{
|
|
name: "present, invalid, last",
|
|
rval: true,
|
|
password: pwdPlain,
|
|
cc: types.CredentialSet{
|
|
&types.Credential{ID: 2, Credentials: pwdUnknown},
|
|
&types.Credential{ID: 3, Credentials: ""},
|
|
&types.Credential{ID: 1, Credentials: pwdHashed, DeletedAt: now()},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
rsp = isPasswordReused(c.cc, c.password, c.window)
|
|
)
|
|
|
|
if c.rval {
|
|
req.True(rsp)
|
|
} else {
|
|
req.False(rsp)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateToken(t *testing.T) {
|
|
type args struct {
|
|
token string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantID uint64
|
|
wantCredentials string
|
|
}{
|
|
{
|
|
name: "empty",
|
|
wantID: 0,
|
|
wantCredentials: "",
|
|
args: args{token: ""}},
|
|
{
|
|
name: "foo",
|
|
wantID: 0,
|
|
wantCredentials: "",
|
|
args: args{token: "foo1"}},
|
|
{
|
|
name: "semivalid",
|
|
wantID: 0,
|
|
wantCredentials: "",
|
|
args: args{token: "foofoofoofoofoofoofoofoofoofoofo0"}},
|
|
{
|
|
name: "valid",
|
|
wantID: 1,
|
|
wantCredentials: "foofoofoofoofoofoofoofoofoofoofo",
|
|
args: args{token: "foofoofoofoofoofoofoofoofoofoofo1"}},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
gotID, gotCredentials := validateToken(tt.args.token)
|
|
|
|
if gotID != tt.wantID {
|
|
t.Errorf("auth.validateToken() gotID = %v, want %v", gotID, tt.wantID)
|
|
}
|
|
if gotCredentials != tt.wantCredentials {
|
|
t.Errorf("auth.validateToken() gotCredentials = %v, want %v", gotCredentials, tt.wantCredentials)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_checkPasswordStrength(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
pc types.PasswordConstraints
|
|
password string
|
|
want bool
|
|
}{
|
|
{
|
|
name: "empty",
|
|
pc: types.PasswordConstraints{},
|
|
password: "",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "sys too short",
|
|
pc: types.PasswordConstraints{},
|
|
password: strings.Repeat("A", passwordMinLength-1),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "sys too long",
|
|
pc: types.PasswordConstraints{},
|
|
password: strings.Repeat("A", passwordMaxLength+1),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "too short",
|
|
pc: types.PasswordConstraints{MinLength: 10},
|
|
password: "123456789",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "uc valid",
|
|
pc: types.PasswordConstraints{MinUpperCase: 2},
|
|
password: "aaaAAAaaa",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "uc invalid",
|
|
pc: types.PasswordConstraints{MinUpperCase: 2},
|
|
password: "aaaaaaaa",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "lc valid",
|
|
pc: types.PasswordConstraints{MinLowerCase: 2},
|
|
password: "AAAaaAAAA",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "lc invalid",
|
|
pc: types.PasswordConstraints{MinLowerCase: 2},
|
|
password: "AAAAAAAAA",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "digit valid",
|
|
pc: types.PasswordConstraints{MinNumCount: 2},
|
|
password: "AAA12AAAA",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "digit invalid",
|
|
pc: types.PasswordConstraints{MinNumCount: 2},
|
|
password: "AAAaaAAAA",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "special valid",
|
|
pc: types.PasswordConstraints{MinSpecialCount: 2},
|
|
password: "AAA!!AAAA",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "special invalid",
|
|
pc: types.PasswordConstraints{MinSpecialCount: 2},
|
|
password: "AAAaaAAAA",
|
|
want: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.pc.PasswordSecurity = true
|
|
if got := checkPasswordStrength(tt.password, tt.pc); got != tt.want {
|
|
t.Errorf("checkPasswordStrength() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|