1
2
3
4 package de.powerstat.validation.values.strategies;
5
6
7 import java.util.HashSet;
8 import java.util.Map;
9 import java.util.Objects;
10 import java.util.Set;
11 import java.util.concurrent.ConcurrentHashMap;
12
13 import de.powerstat.validation.containers.NTuple9;
14
15
16
17
18
19
20
21
22
23
24
25
26 public class PasswordConfigurableStrategy implements IPasswordStrategy
27 {
28
29
30
31 private static final Map<NTuple9<Integer, Integer, String, Integer, Integer, Integer, Integer, Integer, Integer>, PasswordConfigurableStrategy> CACHE = new ConcurrentHashMap<>();
32
33
34
35
36 private final int minLength;
37
38
39
40
41 private final int maxLength;
42
43
44
45
46 private final String regexp;
47
48
49
50
51 private final int minNumeric;
52
53
54
55
56 private final int minLower;
57
58
59
60
61 private final int minUpper;
62
63
64
65
66 private final int minSpecial;
67
68
69
70
71 private final int minUnique;
72
73
74
75
76 private final int maxRepeated;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 protected PasswordConfigurableStrategy(final int minLength, final int maxLength, final String regexp, final int minNumeric, final int minLower, final int minUpper, final int minSpecial, final int minUnique, final int maxRepeated)
96 {
97 super();
98 Objects.requireNonNull(regexp, "regexp");
99 if (minLength <= 0)
100 {
101 throw new IllegalArgumentException("minLength must be >= 1");
102 }
103 if (maxLength < minLength)
104 {
105 throw new IllegalArgumentException("maxLength >= minLength");
106 }
107 if ((regexp.charAt(0) != '^') || !regexp.endsWith("$"))
108 {
109 throw new IllegalArgumentException("regexp does not start with ^ or ends with $");
110 }
111 if ((minNumeric < 0) || (minNumeric > maxLength))
112 {
113 throw new IllegalArgumentException("minNumeric must be >= 0 && <= maxLength");
114 }
115 if ((minLower < 0) || (minLower > maxLength))
116 {
117 throw new IllegalArgumentException("minLower must be >= 0 && <= maxLength");
118 }
119 if ((minUpper < 0) || (minUpper > maxLength))
120 {
121 throw new IllegalArgumentException("minUpper must be >= 0 && <= maxLength");
122 }
123 if ((minSpecial < 0) || (minSpecial > maxLength))
124 {
125 throw new IllegalArgumentException("minSpecial must be >= 0 && <= maxLength");
126 }
127 if ((minNumeric + minLower + minUpper + minSpecial) > maxLength)
128 {
129 throw new IllegalArgumentException("minNumeric + minLower + minUpper + minSpecial > maxLength");
130 }
131 if ((minUnique < 0) || (minUnique > maxLength))
132 {
133 throw new IllegalArgumentException("minUnique must be >= 0 && <= maxLength");
134 }
135 if ((maxRepeated < 0) || (maxRepeated > maxLength))
136 {
137 throw new IllegalArgumentException("maxRepeated must be >= 0 && <= maxLength");
138 }
139 this.minLength = minLength;
140 this.maxLength = maxLength;
141 this.regexp = regexp;
142 this.minNumeric = minNumeric;
143 this.minLower = minLower;
144 this.minUpper = minUpper;
145 this.minSpecial = minSpecial;
146 this.minUnique = minUnique;
147 this.maxRepeated = maxRepeated;
148 }
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 public static IPasswordStrategy of(final int minLength, final int maxLength, final String regexp, final int minNumeric, final int minLower, final int minUpper, final int minSpecial, final int minUnique, final int maxRepeated)
168 {
169 final NTuple9<Integer, Integer, String, Integer, Integer, Integer, Integer, Integer, Integer> tuple = NTuple9.of(minLength, maxLength, regexp, minNumeric, minLower, minUpper, minSpecial, minUnique, maxRepeated);
170 synchronized (PasswordConfigurableStrategy.class)
171 {
172 PasswordConfigurableStrategy obj = PasswordConfigurableStrategy.CACHE.get(tuple);
173 if (obj != null)
174 {
175 return obj;
176 }
177 obj = new PasswordConfigurableStrategy(minLength, maxLength, regexp, minNumeric, minLower, minUpper, minSpecial, minUnique, maxRepeated);
178 PasswordConfigurableStrategy.CACHE.put(tuple, obj);
179 return obj;
180 }
181 }
182
183
184
185
186
187
188
189
190 @Override
191 public void validationStrategy(final String password)
192 {
193 if ((password.length() < this.minLength) || (password.length() > this.maxLength))
194 {
195 throw new IllegalArgumentException("To short or long for a password");
196 }
197 if (!password.matches(this.regexp))
198 {
199 throw new IllegalArgumentException("Password contains illegal character");
200 }
201 int upper = 0;
202 int lower = 0;
203 int numeric = 0;
204 int special = 0;
205 int same = 1;
206 char lastChar = '\0';
207 final Set<Character> cset = new HashSet<>(password.length());
208 for (int i = 0; i < password.length(); ++i)
209 {
210 final char chr = password.charAt(i);
211 cset.add(chr);
212 if (Character.isUpperCase(chr))
213 {
214 ++upper;
215 }
216 else if (Character.isLowerCase(chr))
217 {
218 ++lower;
219 }
220 else if (Character.isDigit(chr))
221 {
222 ++numeric;
223 }
224 else
225 {
226 ++special;
227 }
228 if (chr == lastChar)
229 {
230 ++same;
231 if ((this.maxRepeated != 0) && (same > this.maxRepeated))
232 {
233 throw new IllegalArgumentException("To much repeated characters after each other in password");
234 }
235 }
236 else
237 {
238 same = 1;
239 lastChar = chr;
240 }
241 }
242 if (numeric < this.minNumeric)
243 {
244 throw new IllegalArgumentException("Not enougth numeric characters in password");
245 }
246 if (lower < this.minLower)
247 {
248 throw new IllegalArgumentException("Not enougth lower case characters in password");
249 }
250 if (upper < this.minUpper)
251 {
252 throw new IllegalArgumentException("Not enougth upper case characters in password");
253 }
254 if (special < this.minSpecial)
255 {
256 throw new IllegalArgumentException("Not enougth special characters in password");
257 }
258 if (cset.size() < this.minUnique)
259 {
260 throw new IllegalArgumentException("Not enougth unique characters in password");
261 }
262 }
263
264 }