Skip to content

Commit d4b8210

Browse files
committed
HV-2067 Adjust UUID's version/variant validation
1 parent bb039fd commit d4b8210

File tree

3 files changed

+177
-11
lines changed

3 files changed

+177
-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
@@ -60,29 +60,77 @@
6060

6161
/**
6262
* @return allow empty strings.
63-
* Per default does not allow empty strings
63+
* Per default does not allow empty strings.
6464
*/
6565
boolean allowEmpty() default false;
6666

6767
/**
68-
* @return {@code true} if nil UUIDs {@code 00000000-0000-0000-0000-000000000000} are valid
69-
* Per default nil UUIDs are valid
68+
* @return {@code true} if nil UUIDs {@code 00000000-0000-0000-0000-000000000000} are valid.
69+
* Per default nil UUIDs are valid.
7070
*/
7171
boolean allowNil() default true;
7272

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

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

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
@@ -121,12 +121,11 @@ else if ( valueLength != 36 ) {
121121
return allowNil;
122122
}
123123
else {
124-
if ( Arrays.binarySearch( this.version, version ) == -1 ) {
124+
if ( Arrays.binarySearch( this.version, version ) < 0 ) {
125125
return false;
126126
}
127-
return Arrays.binarySearch( this.variant, variant ) != -1;
127+
return Arrays.binarySearch( this.variant, variant ) > -1;
128128
}
129-
130129
}
131130

132131
/**

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

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
import org.testng.annotations.BeforeMethod;
1515
import org.testng.annotations.Test;
1616

17+
import static org.assertj.core.api.Assertions.assertThat;
1718
import static org.testng.Assert.assertFalse;
1819
import static org.testng.Assert.assertTrue;
1920
import static org.testng.Assert.fail;
2021

22+
import java.util.Locale;
23+
2124
/**
2225
* Tests the {@link UUID} constraint.
2326
*
@@ -289,5 +292,121 @@ public void validOnlyIfConfiguredVariantMatches() {
289292

290293
}
291294

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

388+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
389+
uuidValidator.initialize( uuidAnnotation );
390+
391+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) );
392+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) );
393+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) );
394+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) );
395+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) );
396+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) );
397+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) );
398+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) );
399+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) );
400+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) );
401+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) );
402+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) );
403+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
404+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) );
405+
// Next two variants are always invalid as they are currently "undefined":
406+
// 1110 e
407+
// 1111 f
408+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) );
409+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) );
410+
411+
}
293412
}

0 commit comments

Comments
 (0)