Skip to content

Commit

Permalink
HV-2067 Adjust UUID's version/variant validation
Browse files Browse the repository at this point in the history
  • Loading branch information
marko-bekhta committed Dec 12, 2024
1 parent 7b3cce5 commit 7eacecb
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 11 deletions.
64 changes: 56 additions & 8 deletions engine/src/main/java/org/hibernate/validator/constraints/UUID.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,29 +57,77 @@

/**
* @return allow empty strings.
* Per default does not allow empty strings
* Per default does not allow empty strings.
*/
boolean allowEmpty() default false;

/**
* @return {@code true} if nil UUIDs {@code 00000000-0000-0000-0000-000000000000} are valid
* Per default nil UUIDs are valid
* @return {@code true} if nil UUIDs {@code 00000000-0000-0000-0000-000000000000} are valid.
* Per default nil UUIDs are valid.
*/
boolean allowNil() default true;

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

/**
* Must not be lower than variant 0
* Accepts values in the {@code [0; 2]} range.
* <p>
* The variant of the UUID is determined by the binary representation of the 17th hex digit
* ({@code xxxxxxxx-xxxx-xxxx-Vxxx-xxxxxxxxxxxx} where {@code V} is the variant digit).
* <p>
* Currently, only variants {@code [0, 1, 2]} are supported by the validator:
* <table>
* <caption>Table 1</caption>
* <thead>
* <tr>
* <th>Variant #</th>
* <th>Binary Representation</th>
* <th>Hex Digit</th>
* <th>Comment</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td>0</td>
* <td>0xxx</td>
* <td>0 - 7</td>
* <td></td>
* </tr>
* <tr>
* <td>1</td>
* <td>10xx</td>
* <td>8 - b</td>
* <td></td>
* </tr>
* <tr>
* <td>2</td>
* <td>110x</td>
* <td>c - d</td>
* <td></td>
* </tr>
* <tr>
* <td>-</td>
* <td>1110</td>
* <td>e</td>
* <td>Unsupported, an UUID with such variant will be considered invalid.</td>
* </tr>
* <tr>
* <td>-</td>
* <td>1111</td>
* <td>f</td>
* <td>Unsupported, an UUID with such variant will be considered invalid.</td>
* </tr>
* </tbody>
* </table>
*
* @return the allowed UUID variant numbers
* Per default variants 0 to 2 are allowed
* Per default, all variants 0 to 2 are allowed
*/
int[] variant() default { 0, 1, 2 };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,11 @@ else if ( valueLength != 36 ) {
return allowNil;
}
else {
if ( Arrays.binarySearch( this.version, version ) == -1 ) {
if ( Arrays.binarySearch( this.version, version ) < 0 ) {
return false;
}
return Arrays.binarySearch( this.variant, variant ) != -1;
return Arrays.binarySearch( this.variant, variant ) > -1;
}

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package org.hibernate.validator.test.internal.constraintvalidators.hv;

import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
Expand Down Expand Up @@ -287,5 +288,121 @@ public void validOnlyIfConfiguredVariantMatches() {

}

@Test
public void versionNotInTheAllowedList() {
char[] versions = new char[] { '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

for ( int i = 0; i < versions.length; i++ ) {
int version = Character.digit( versions[i], 16 );
descriptorBuilder.setAttribute( "version", new int[] { version } );

uuidAnnotation = descriptorBuilder.build().getAnnotation();
uuidValidator.initialize( uuidAnnotation );

for ( int j = 0; j < versions.length; j++ ) {
if ( i == j ) {
continue;
}
String uuid = "24e6abaa-b2a8-%sa8e-0622-92adaaae229f".formatted( versions[j] );
assertThat( uuidValidator.isValid( uuid, null ) )
.as( "Expected uuid %s to be invalid because of the version %s not being allowed", uuid, versions[j] )
.isFalse();
}
}
}

@Test
public void variantNotInTheAllowedLis11t() {
descriptorBuilder.setAttribute( "variant", new int[] { 1 } );

uuidAnnotation = descriptorBuilder.build().getAnnotation();
uuidValidator.initialize( uuidAnnotation );

assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
}

@Test
public void variantNotInTheAllowedList() {
// 0xxx 0 - 7 reserved (NCS backward compatible)
// 10xx 8 - b DCE 1.1, ISO/IEC 11578:1996
// 110x c - d reserved (Microsoft GUID)
// 1110 e reserved (future use)
// 1111 f unknown / invalid. Must end with "0"

descriptorBuilder.setAttribute( "variant", new int[] { 0 } );

uuidAnnotation = descriptorBuilder.build().getAnnotation();
uuidValidator.initialize( uuidAnnotation );

assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) );
// Next two variants are always invalid as they are currently "undefined":
// 1110 e
// 1111 f
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) );

descriptorBuilder.setAttribute( "variant", new int[] { 1 } );

uuidAnnotation = descriptorBuilder.build().getAnnotation();
uuidValidator.initialize( uuidAnnotation );

assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) );
// Next two variants are always invalid as they are currently "undefined":
// 1110 e
// 1111 f
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) );

descriptorBuilder.setAttribute( "variant", new int[] { 2 } );

uuidAnnotation = descriptorBuilder.build().getAnnotation();
uuidValidator.initialize( uuidAnnotation );

assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) );
// Next two variants are always invalid as they are currently "undefined":
// 1110 e
// 1111 f
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) );
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) );

}
}

0 comments on commit 7eacecb

Please sign in to comment.