Skip to content

Commit 7eacecb

Browse files
committed
HV-2067 Adjust UUID's version/variant validation
1 parent 7b3cce5 commit 7eacecb

File tree

3 files changed

+175
-11
lines changed

3 files changed

+175
-11
lines changed

engine/src/main/java/org/hibernate/validator/constraints/UUID.java

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,29 +57,77 @@
5757

5858
/**
5959
* @return allow empty strings.
60-
* Per default does not allow empty strings
60+
* Per default does not allow empty strings.
6161
*/
6262
boolean allowEmpty() default false;
6363

6464
/**
65-
* @return {@code true} if nil UUIDs {@code 00000000-0000-0000-0000-000000000000} are valid
66-
* Per default nil UUIDs are valid
65+
* @return {@code true} if nil UUIDs {@code 00000000-0000-0000-0000-000000000000} are valid.
66+
* Per default nil UUIDs are valid.
6767
*/
6868
boolean allowNil() default true;
6969

7070
/**
71-
* Must not be lower than version 1
71+
* Accepts values in the {@code [1; 15]} range, which corresponds to the hexadecimal {@code [1; f]} range.
7272
*
73-
* @return the accepted UUID version numbers
74-
* Per default versions 1 to 5 are allowed
73+
* @return the accepted UUID version numbers.
74+
* Per default, versions 1 through 5 are allowed.
7575
*/
7676
int[] version() default { 1, 2, 3, 4, 5 };
7777

7878
/**
79-
* Must not be lower than variant 0
79+
* Accepts values in the {@code [0; 2]} range.
80+
* <p>
81+
* The variant of the UUID is determined by the binary representation of the 17th hex digit
82+
* ({@code xxxxxxxx-xxxx-xxxx-Vxxx-xxxxxxxxxxxx} where {@code V} is the variant digit).
83+
* <p>
84+
* Currently, only variants {@code [0, 1, 2]} are supported by the validator:
85+
* <table>
86+
* <caption>Table 1</caption>
87+
* <thead>
88+
* <tr>
89+
* <th>Variant #</th>
90+
* <th>Binary Representation</th>
91+
* <th>Hex Digit</th>
92+
* <th>Comment</th>
93+
* </tr>
94+
* </thead>
95+
* <tbody>
96+
* <tr>
97+
* <td>0</td>
98+
* <td>0xxx</td>
99+
* <td>0 - 7</td>
100+
* <td></td>
101+
* </tr>
102+
* <tr>
103+
* <td>1</td>
104+
* <td>10xx</td>
105+
* <td>8 - b</td>
106+
* <td></td>
107+
* </tr>
108+
* <tr>
109+
* <td>2</td>
110+
* <td>110x</td>
111+
* <td>c - d</td>
112+
* <td></td>
113+
* </tr>
114+
* <tr>
115+
* <td>-</td>
116+
* <td>1110</td>
117+
* <td>e</td>
118+
* <td>Unsupported, an UUID with such variant will be considered invalid.</td>
119+
* </tr>
120+
* <tr>
121+
* <td>-</td>
122+
* <td>1111</td>
123+
* <td>f</td>
124+
* <td>Unsupported, an UUID with such variant will be considered invalid.</td>
125+
* </tr>
126+
* </tbody>
127+
* </table>
80128
*
81129
* @return the allowed UUID variant numbers
82-
* Per default variants 0 to 2 are allowed
130+
* Per default, all variants 0 to 2 are allowed
83131
*/
84132
int[] variant() default { 0, 1, 2 };
85133

engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/hv/UUIDValidator.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,11 @@ else if ( valueLength != 36 ) {
119119
return allowNil;
120120
}
121121
else {
122-
if ( Arrays.binarySearch( this.version, version ) == -1 ) {
122+
if ( Arrays.binarySearch( this.version, version ) < 0 ) {
123123
return false;
124124
}
125-
return Arrays.binarySearch( this.variant, variant ) != -1;
125+
return Arrays.binarySearch( this.variant, variant ) > -1;
126126
}
127-
128127
}
129128

130129
/**

engine/src/test/java/org/hibernate/validator/test/internal/constraintvalidators/hv/UUIDValidatorTest.java

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.validator.test.internal.constraintvalidators.hv;
66

7+
import static org.assertj.core.api.Assertions.assertThat;
78
import static org.testng.Assert.assertFalse;
89
import static org.testng.Assert.assertTrue;
910
import static org.testng.Assert.fail;
@@ -287,5 +288,121 @@ public void validOnlyIfConfiguredVariantMatches() {
287288

288289
}
289290

291+
@Test
292+
public void versionNotInTheAllowedList() {
293+
char[] versions = new char[] { '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
294+
295+
for ( int i = 0; i < versions.length; i++ ) {
296+
int version = Character.digit( versions[i], 16 );
297+
descriptorBuilder.setAttribute( "version", new int[] { version } );
298+
299+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
300+
uuidValidator.initialize( uuidAnnotation );
301+
302+
for ( int j = 0; j < versions.length; j++ ) {
303+
if ( i == j ) {
304+
continue;
305+
}
306+
String uuid = "24e6abaa-b2a8-%sa8e-0622-92adaaae229f".formatted( versions[j] );
307+
assertThat( uuidValidator.isValid( uuid, null ) )
308+
.as( "Expected uuid %s to be invalid because of the version %s not being allowed", uuid, versions[j] )
309+
.isFalse();
310+
}
311+
}
312+
}
313+
314+
@Test
315+
public void variantNotInTheAllowedLis11t() {
316+
descriptorBuilder.setAttribute( "variant", new int[] { 1 } );
317+
318+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
319+
uuidValidator.initialize( uuidAnnotation );
320+
321+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
322+
}
323+
324+
@Test
325+
public void variantNotInTheAllowedList() {
326+
// 0xxx 0 - 7 reserved (NCS backward compatible)
327+
// 10xx 8 - b DCE 1.1, ISO/IEC 11578:1996
328+
// 110x c - d reserved (Microsoft GUID)
329+
// 1110 e reserved (future use)
330+
// 1111 f unknown / invalid. Must end with "0"
331+
332+
descriptorBuilder.setAttribute( "variant", new int[] { 0 } );
333+
334+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
335+
uuidValidator.initialize( uuidAnnotation );
336+
337+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) );
338+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) );
339+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) );
340+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) );
341+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) );
342+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) );
343+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) );
344+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) );
345+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) );
346+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) );
347+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) );
348+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) );
349+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
350+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) );
351+
// Next two variants are always invalid as they are currently "undefined":
352+
// 1110 e
353+
// 1111 f
354+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) );
355+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) );
356+
357+
descriptorBuilder.setAttribute( "variant", new int[] { 1 } );
358+
359+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
360+
uuidValidator.initialize( uuidAnnotation );
290361

362+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) );
363+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) );
364+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) );
365+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) );
366+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) );
367+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) );
368+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) );
369+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) );
370+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) );
371+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) );
372+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) );
373+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) );
374+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
375+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) );
376+
// Next two variants are always invalid as they are currently "undefined":
377+
// 1110 e
378+
// 1111 f
379+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) );
380+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) );
381+
382+
descriptorBuilder.setAttribute( "variant", new int[] { 2 } );
383+
384+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
385+
uuidValidator.initialize( uuidAnnotation );
386+
387+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) );
388+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) );
389+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) );
390+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) );
391+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) );
392+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) );
393+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) );
394+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) );
395+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) );
396+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) );
397+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) );
398+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) );
399+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
400+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) );
401+
// Next two variants are always invalid as they are currently "undefined":
402+
// 1110 e
403+
// 1111 f
404+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) );
405+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) );
406+
407+
}
291408
}

0 commit comments

Comments
 (0)