From 86313fda247849f3f1abd90fa2124083dd2f403c Mon Sep 17 00:00:00 2001 From: Hardik Kaurani Date: Thu, 22 Oct 2026 11:21:26 +0530 Subject: [PATCH 1/2] fix(abstractions): add null checks and reject userinfo in AllowedHostsValidator --- .../authentication/AllowedHostsValidator.java | 24 ++++++++++++--- .../AllowedHostValidatorTest.java | 29 +++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AllowedHostsValidator.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AllowedHostsValidator.java index 5da5529d..38d230ab 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AllowedHostsValidator.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AllowedHostsValidator.java @@ -1,6 +1,7 @@ package com.microsoft.kiota.authentication; import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import java.net.URI; import java.util.Collections; @@ -57,16 +58,31 @@ public void setAllowedHosts(@Nonnull final Set allowedHosts) { * @param uri the uri to check the host for. * @return true if the host is allowed, false otherwise. */ - public boolean isUrlHostValid(@Nonnull final URI uri) { + public boolean isUrlHostValid(@Nullable final URI uri) { + if (uri == null) { + return false; + } + final String scheme = uri.getScheme(); + if (scheme == null || scheme.trim().isEmpty()) { + return false; + } + final String userInfo = uri.getUserInfo(); + if (userInfo != null && !userInfo.isEmpty()) { + return false; + } + final String host = uri.getHost(); + if (host == null || host.trim().isEmpty()) { + return false; + } if (validHosts.isEmpty()) { return true; } - final String host = uri.getHost().trim().toLowerCase(Locale.ROOT); - if (validHosts.contains(host)) { + final String normalizedHost = host.trim().toLowerCase(Locale.ROOT); + if (validHosts.contains(normalizedHost)) { return true; } for (final String validHost : validHosts) { - if (validHost.startsWith(".") && host.endsWith(validHost)) { + if (validHost.startsWith(".") && normalizedHost.endsWith(validHost)) { return true; } } diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/authentication/AllowedHostValidatorTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/authentication/AllowedHostValidatorTest.java index 6f1a54b0..4d987095 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/authentication/AllowedHostValidatorTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/authentication/AllowedHostValidatorTest.java @@ -93,4 +93,33 @@ void allowsSuffixBasedHostsAfterUpdate() throws URISyntaxException { validator.isUrlHostValid( new URI("https://abc.123.graphql.fabric.microsoft.com/path"))); } + + @Test + void returnsFalseForNullUri() { + final AllowedHostsValidator validator = new AllowedHostsValidator("example.com"); + assertFalse(validator.isUrlHostValid(null)); + } + + @Test + void returnsFalseForUriWithoutSchemeOrHost() throws URISyntaxException { + final AllowedHostsValidator validator = new AllowedHostsValidator("example.com"); + assertFalse(validator.isUrlHostValid(new URI("mailto:test@example.com"))); + assertFalse(validator.isUrlHostValid(new URI("/path/only"))); + } + + @Test + void returnsFalseForUriWithUserInfo() throws URISyntaxException { + final AllowedHostsValidator validator = new AllowedHostsValidator("example.com"); + assertFalse(validator.isUrlHostValid(new URI("https://user:password@example.com/path"))); + assertFalse(validator.isUrlHostValid(new URI("https://user@example.com/path"))); + } + + @Test + void validatesUriEvenWhenAllowedHostsEmpty() throws URISyntaxException { + final AllowedHostsValidator validator = new AllowedHostsValidator(); + assertFalse(validator.isUrlHostValid(null)); + assertFalse(validator.isUrlHostValid(new URI("mailto:test@example.com"))); + assertFalse(validator.isUrlHostValid(new URI("https://user:pass@example.com/path"))); + assertTrue(validator.isUrlHostValid(new URI("https://anything.com/path"))); + } } From 2d75b3f693bd1f4d634ecdcd76131c66296ac99e Mon Sep 17 00:00:00 2001 From: Hardik Kaurani Date: Fri, 23 Oct 2026 19:36:09 +0530 Subject: [PATCH 2/2] fix(abstractions): retain @Nonnull constraint on isUrlHostValid and fail-fast with Objects.requireNonNull --- .../kiota/authentication/AllowedHostsValidator.java | 8 +++----- .../kiota/authentication/AllowedHostValidatorTest.java | 9 ++++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AllowedHostsValidator.java b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AllowedHostsValidator.java index 38d230ab..cc858788 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AllowedHostsValidator.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AllowedHostsValidator.java @@ -1,12 +1,12 @@ package com.microsoft.kiota.authentication; import jakarta.annotation.Nonnull; -import jakarta.annotation.Nullable; import java.net.URI; import java.util.Collections; import java.util.HashSet; import java.util.Locale; +import java.util.Objects; import java.util.Set; /** Maintains a list of valid hosts and allows authentication providers to check whether a host is valid before authenticating a request */ @@ -58,10 +58,8 @@ public void setAllowedHosts(@Nonnull final Set allowedHosts) { * @param uri the uri to check the host for. * @return true if the host is allowed, false otherwise. */ - public boolean isUrlHostValid(@Nullable final URI uri) { - if (uri == null) { - return false; - } + public boolean isUrlHostValid(@Nonnull final URI uri) { + Objects.requireNonNull(uri, "parameter uri cannot be null"); final String scheme = uri.getScheme(); if (scheme == null || scheme.trim().isEmpty()) { return false; diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/authentication/AllowedHostValidatorTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/authentication/AllowedHostValidatorTest.java index 4d987095..3fd66094 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/authentication/AllowedHostValidatorTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/authentication/AllowedHostValidatorTest.java @@ -12,6 +12,9 @@ import java.util.Collections; class AllowedHostValidatorTest { + private static T nullValue() { + return java.util.Collections.emptyMap().get("missing"); + } @Test void throwsExceptionForHttpOrHttpsHosts() { @@ -95,9 +98,9 @@ void allowsSuffixBasedHostsAfterUpdate() throws URISyntaxException { } @Test - void returnsFalseForNullUri() { + void throwsNullPointerExceptionForNullUri() { final AllowedHostsValidator validator = new AllowedHostsValidator("example.com"); - assertFalse(validator.isUrlHostValid(null)); + assertThrows(NullPointerException.class, () -> validator.isUrlHostValid(nullValue())); } @Test @@ -117,7 +120,7 @@ void returnsFalseForUriWithUserInfo() throws URISyntaxException { @Test void validatesUriEvenWhenAllowedHostsEmpty() throws URISyntaxException { final AllowedHostsValidator validator = new AllowedHostsValidator(); - assertFalse(validator.isUrlHostValid(null)); + assertThrows(NullPointerException.class, () -> validator.isUrlHostValid(nullValue())); assertFalse(validator.isUrlHostValid(new URI("mailto:test@example.com"))); assertFalse(validator.isUrlHostValid(new URI("https://user:pass@example.com/path"))); assertTrue(validator.isUrlHostValid(new URI("https://anything.com/path")));