diff --git a/web/src/main/java/org/springframework/security/web/util/matcher/IpAddressMatcher.java b/web/src/main/java/org/springframework/security/web/util/matcher/IpAddressMatcher.java index 80c344fb27..c2f547e48b 100644 --- a/web/src/main/java/org/springframework/security/web/util/matcher/IpAddressMatcher.java +++ b/web/src/main/java/org/springframework/security/web/util/matcher/IpAddressMatcher.java @@ -18,6 +18,7 @@ package org.springframework.security.web.util.matcher; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.Scanner; import jakarta.servlet.http.HttpServletRequest; @@ -47,7 +48,7 @@ public final class IpAddressMatcher implements RequestMatcher { * come. */ public IpAddressMatcher(String ipAddress) { - assertStartsWithHexa(ipAddress); + assertNotHostName(ipAddress); if (ipAddress.indexOf('/') > 0) { String[] addressAndMask = StringUtils.split(ipAddress, "/"); ipAddress = addressAndMask[0]; @@ -68,7 +69,7 @@ public final class IpAddressMatcher implements RequestMatcher { } public boolean matches(String address) { - assertStartsWithHexa(address); + assertNotHostName(address); InetAddress remoteAddress = parseAddress(address); if (!this.requiredAddress.getClass().equals(remoteAddress.getClass())) { return false; @@ -91,11 +92,17 @@ public final class IpAddressMatcher implements RequestMatcher { return true; } - private void assertStartsWithHexa(String ipAddress) { - Assert.isTrue( - ipAddress.charAt(0) == '[' || ipAddress.charAt(0) == ':' - || Character.digit(ipAddress.charAt(0), 16) != -1, - "ipAddress must start with a [, :, or a hexadecimal digit"); + private void assertNotHostName(String ipAddress) { + String error = "ipAddress " + ipAddress + " doesn't look like an IP Address. Is it a host name?"; + Assert.isTrue(ipAddress.charAt(0) == '[' || ipAddress.charAt(0) == ':' + || Character.digit(ipAddress.charAt(0), 16) != -1, error); + if (!ipAddress.contains(":")) { + Scanner parts = new Scanner(ipAddress); + parts.useDelimiter("[./]"); + while (parts.hasNext()) { + Assert.isTrue(parts.hasNextInt() && parts.nextInt() >> 8 == 0, error); + } + } } private InetAddress parseAddress(String address) { diff --git a/web/src/test/java/org/springframework/security/web/util/matcher/IpAddressMatcherTests.java b/web/src/test/java/org/springframework/security/web/util/matcher/IpAddressMatcherTests.java index 17c2bbadb3..eebd8fa945 100644 --- a/web/src/test/java/org/springframework/security/web/util/matcher/IpAddressMatcherTests.java +++ b/web/src/test/java/org/springframework/security/web/util/matcher/IpAddressMatcherTests.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import org.springframework.mock.web.MockHttpServletRequest; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; /** @@ -108,7 +109,21 @@ public class IpAddressMatcherTests { @Test public void invalidAddressThenIllegalArgumentException() { assertThatIllegalArgumentException().isThrownBy(() -> new IpAddressMatcher("invalid-ip")) - .withMessage("ipAddress must start with a [, :, or a hexadecimal digit"); + .withMessage("ipAddress invalid-ip doesn't look like an IP Address. Is it a host name?"); + } + + // gh-15172 + @Test + public void hexadecimalDomainNameThenIllegalArgumentException() { + assertThatException().isThrownBy(() -> new IpAddressMatcher("deadbeef.abc")) + .withMessage("ipAddress deadbeef.abc doesn't look like an IP Address. Is it a host name?"); + } + + // gh-15172 + @Test + public void numericDomainNameThenIllegalArgumentException() { + assertThatException().isThrownBy(() -> new IpAddressMatcher("123.156.7.18.org")) + .withMessage("ipAddress 123.156.7.18.org doesn't look like an IP Address. Is it a host name?"); } }