Skip to content

Commit c6fd98c

Browse files
authored
Merge pull request #674 from fmount/pwd_validation
Enhance password validation tests with more test vectors
2 parents 9818242 + fb83fe1 commit c6fd98c

1 file changed

Lines changed: 215 additions & 133 deletions

File tree

modules/common/secret/password_test.go

Lines changed: 215 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,21 @@ package secret
1919
import (
2020
. "github.com/onsi/gomega" // nolint:revive
2121
"regexp"
22+
"slices"
2223
"testing"
2324
)
2425

2526
const ErrMsg string = "password does not meet the requirements"
2627

28+
// TestVector -
29+
type TestVector struct {
30+
name string
31+
password string
32+
wantErr bool
33+
errMsg string
34+
}
35+
36+
// Pattern definition (requirements and reject rules)
2737
var testRequirements []Rule = []Rule{
2838
{
2939
description: "Must contain at least one digit",
@@ -50,6 +60,201 @@ var testRejects []Rule = []Rule{
5060
},
5161
}
5262

63+
// Input TestVectors
64+
// 1. Fernet pattern
65+
// 2. alphaNumPattern
66+
// 3. validPattern
67+
// 4. Invalid patterns
68+
var fernetPattern []TestVector = []TestVector{
69+
// Fernet pattern:
70+
// python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode(' UTF-8'))";
71+
{
72+
name: "Fernet Pattern Test 1",
73+
password: "dzUSgMefMDi3Mrq-PF8p4lHoOdF-ps_oDQB9-KzS-j0=",
74+
wantErr: false,
75+
},
76+
{
77+
name: "Fernet Pattern Test 2",
78+
password: "7Q0cfVtxqzZMKWhY5LJQF4sImYyOvC_BYYd-yg2GvUg=",
79+
wantErr: false,
80+
},
81+
{
82+
name: "Fernet Pattern Test 3",
83+
password: "UjQSpLh2WGEIFZ1Y-QCSiUr4aE76Wu3YdYLTStyEK1c=",
84+
wantErr: false,
85+
},
86+
{
87+
name: "Fernet Pattern Test 4",
88+
password: "UWtR_BCTgszn2kDhz_yxBoxxiHytMB1IR0t200uRD2s=",
89+
wantErr: false,
90+
},
91+
{
92+
name: "Fernet Pattern Test 5",
93+
password: "7cXj_fYimZ1WNu_87kNj4WM6JaI2KqCL3In2WZhAD7I=",
94+
wantErr: false,
95+
},
96+
}
97+
98+
var alphaNumPattern []TestVector = []TestVector{
99+
// $(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 32 | base64)
100+
{
101+
name: "Default pattern 1",
102+
password: "QTFkZ1U2VnF3RWdXWjZuQW9teUo2dHlEUk43UWtaOHM=",
103+
wantErr: false,
104+
},
105+
{
106+
name: "Default pattern 2",
107+
password: "SlBVUm9OUVhEOWpjOHJsNkJmTENNbnlENjJvMU5yc1A=",
108+
wantErr: false,
109+
},
110+
{
111+
name: "Default pattern 3",
112+
password: "QzA5ejh5a1ZoWVIxbk1LUmZ4elJNMVBQNFNVdzdhaG0=",
113+
wantErr: false,
114+
},
115+
{
116+
name: "Default pattern 4",
117+
password: "ckIwWk1MUnRsSmtqdGFseThmRkYyUlhUUDdXUXhOcmc=",
118+
wantErr: false,
119+
},
120+
{
121+
name: "Default pattern 5",
122+
password: "aUxHdDRDcFR4amM2MXg4bVBoaGU2blBJRHFER3hoMFU=",
123+
wantErr: false,
124+
},
125+
}
126+
127+
var validPattern []TestVector = []TestVector{
128+
// Valid password scenarios
129+
{
130+
name: "valid password with all requirements",
131+
password: "Password123",
132+
wantErr: false,
133+
},
134+
{
135+
name: "valid password with minimum length",
136+
password: "Abcdef12",
137+
wantErr: false,
138+
},
139+
{
140+
name: "valid password with longer length",
141+
password: "MySecurePassword123",
142+
wantErr: false,
143+
},
144+
{
145+
name: "valid password with allowed special characters",
146+
password: "Password123!@+=._-",
147+
wantErr: false,
148+
},
149+
{
150+
name: "valid password with semicolon",
151+
password: "Password123;allowed",
152+
wantErr: false,
153+
},
154+
{
155+
name: "valid password with angle brackets",
156+
password: "Password123<valid>",
157+
wantErr: false,
158+
},
159+
{
160+
name: "valid password with caret character",
161+
password: "Password123^valid",
162+
wantErr: false,
163+
},
164+
{
165+
name: "valid password with percent character",
166+
password: "Password123%valid",
167+
wantErr: false,
168+
},
169+
{
170+
name: "valid password with safe metacharacters",
171+
password: "Password123*?{}[]|&~#'\"",
172+
wantErr: false,
173+
},
174+
{
175+
name: "valid password with isolated dollar and number",
176+
password: "Password123$123",
177+
wantErr: false,
178+
},
179+
}
180+
181+
var invalidPattern []TestVector = []TestVector{
182+
// Invalid password scenarios - shell expansion patterns
183+
{
184+
name: "password made by all numbers",
185+
password: "12345678",
186+
wantErr: true,
187+
},
188+
{
189+
name: "empty password",
190+
password: "",
191+
wantErr: true,
192+
errMsg: "empty password not allowed",
193+
},
194+
{
195+
name: "password without uppercase",
196+
password: "password123",
197+
wantErr: true,
198+
},
199+
{
200+
name: "password without lowercase",
201+
password: "PASSWORD123",
202+
wantErr: true,
203+
},
204+
{
205+
name: "password without digit",
206+
password: "PasswordABC",
207+
wantErr: true,
208+
},
209+
{
210+
name: "password too short",
211+
password: "Pass12",
212+
wantErr: true,
213+
},
214+
{
215+
name: "password with variable expansion",
216+
password: "Password123$HOME",
217+
wantErr: true,
218+
errMsg: ErrMsg,
219+
},
220+
{
221+
name: "password with variable expansion underscore",
222+
password: "Password123$USER_NAME",
223+
wantErr: true,
224+
errMsg: ErrMsg,
225+
},
226+
{
227+
name: "password with braced variable expansion",
228+
password: "Password123${HOME}",
229+
wantErr: true,
230+
errMsg: ErrMsg,
231+
},
232+
{
233+
name: "password with command substitution",
234+
password: "Password123$(echo bad)",
235+
wantErr: true,
236+
errMsg: ErrMsg,
237+
},
238+
{
239+
name: "password with backtick command substitution",
240+
password: "Password123`echo bad`",
241+
wantErr: true,
242+
errMsg: ErrMsg,
243+
},
244+
{
245+
name: "password with complex variable expansion",
246+
password: "Password123${VARIABLE_NAME}",
247+
wantErr: true,
248+
errMsg: ErrMsg,
249+
},
250+
{
251+
name: "shell expansion attack example",
252+
password: "c^sometext02%text%text02$someText&",
253+
wantErr: true,
254+
errMsg: ErrMsg,
255+
},
256+
}
257+
53258
func TestValidatePassword(t *testing.T) {
54259
// Save original values
55260
originalRequirements := requirements
@@ -65,139 +270,16 @@ func TestValidatePassword(t *testing.T) {
65270
rejects = originalRejects
66271
}()
67272

68-
tests := []struct {
69-
name string
70-
password string
71-
wantErr bool
72-
errMsg string
73-
}{
74-
// Valid password scenarios
75-
{
76-
name: "valid password with all requirements",
77-
password: "Password123",
78-
wantErr: false,
79-
},
80-
{
81-
name: "valid password with minimum length",
82-
password: "Abcdef12",
83-
wantErr: false,
84-
},
85-
{
86-
name: "valid password with longer length",
87-
password: "MySecurePassword123",
88-
wantErr: false,
89-
},
90-
{
91-
name: "valid password with allowed special characters",
92-
password: "Password123!@+=._-",
93-
wantErr: false,
94-
},
95-
{
96-
name: "valid password with semicolon",
97-
password: "Password123;allowed",
98-
wantErr: false,
99-
},
100-
{
101-
name: "valid password with angle brackets",
102-
password: "Password123<valid>",
103-
wantErr: false,
104-
},
105-
{
106-
name: "valid password with caret character",
107-
password: "Password123^valid",
108-
wantErr: false,
109-
},
110-
{
111-
name: "valid password with percent character",
112-
password: "Password123%valid",
113-
wantErr: false,
114-
},
115-
{
116-
name: "valid password with safe metacharacters",
117-
password: "Password123*?{}[]|&~#'\"",
118-
wantErr: false,
119-
},
120-
{
121-
name: "valid password with isolated dollar and number",
122-
password: "Password123$123",
123-
wantErr: false,
124-
},
125-
126-
// Invalid password scenarios - shell expansion patterns
127-
{
128-
name: "password made by all numbers",
129-
password: "12345678",
130-
wantErr: true,
131-
},
132-
{
133-
name: "empty password",
134-
password: "",
135-
wantErr: true,
136-
errMsg: "empty password not allowed",
137-
},
138-
{
139-
name: "password without uppercase",
140-
password: "password123",
141-
wantErr: true,
142-
},
143-
{
144-
name: "password without lowercase",
145-
password: "PASSWORD123",
146-
wantErr: true,
147-
},
148-
{
149-
name: "password without digit",
150-
password: "PasswordABC",
151-
wantErr: true,
152-
},
153-
{
154-
name: "password too short",
155-
password: "Pass12",
156-
wantErr: true,
157-
},
158-
{
159-
name: "password with variable expansion",
160-
password: "Password123$HOME",
161-
wantErr: true,
162-
errMsg: ErrMsg,
163-
},
164-
{
165-
name: "password with variable expansion underscore",
166-
password: "Password123$USER_NAME",
167-
wantErr: true,
168-
errMsg: ErrMsg,
169-
},
170-
{
171-
name: "password with braced variable expansion",
172-
password: "Password123${HOME}",
173-
wantErr: true,
174-
errMsg: ErrMsg,
175-
},
176-
{
177-
name: "password with command substitution",
178-
password: "Password123$(echo bad)",
179-
wantErr: true,
180-
errMsg: ErrMsg,
181-
},
182-
{
183-
name: "password with backtick command substitution",
184-
password: "Password123`echo bad`",
185-
wantErr: true,
186-
errMsg: ErrMsg,
187-
},
188-
{
189-
name: "password with complex variable expansion",
190-
password: "Password123${VARIABLE_NAME}",
191-
wantErr: true,
192-
errMsg: ErrMsg,
193-
},
194-
{
195-
name: "shell expansion attack example",
196-
password: "c^sometext02%text%text02$someText&",
197-
wantErr: true,
198-
errMsg: ErrMsg,
199-
},
200-
}
273+
// Build TestVector
274+
var tests []TestVector
275+
tests = slices.Concat(
276+
tests,
277+
validPattern,
278+
invalidPattern,
279+
alphaNumPattern,
280+
fernetPattern,
281+
)
282+
// Execute ValidatePassword against the generated TestVector
201283
for _, tt := range tests {
202284
t.Run(tt.name, func(t *testing.T) {
203285
g := NewWithT(t)

0 commit comments

Comments
 (0)