Skip to content

Commit 285d16b

Browse files
committed
Polish IpAddressMatcher
(cherry picked from commit 83a7915)
1 parent ddf4542 commit 285d16b

File tree

1 file changed

+33
-22
lines changed

1 file changed

+33
-22
lines changed

web/src/main/java/org/springframework/security/web/util/matcher/IpAddressMatcher.java

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.net.InetAddress;
2020
import java.net.UnknownHostException;
21+
import java.util.Objects;
2122
import java.util.regex.Pattern;
2223

2324
import jakarta.servlet.http.HttpServletRequest;
@@ -33,16 +34,17 @@
3334
* IPv4 address will never match a request which returns an IPv6 address, and vice-versa.
3435
*
3536
* @author Luke Taylor
37+
* @author Steve Riesenberg
3638
* @since 3.0.2
3739
*/
3840
public final class IpAddressMatcher implements RequestMatcher {
3941

4042
private static Pattern IPV4 = Pattern.compile("\\d{0,3}.\\d{0,3}.\\d{0,3}.\\d{0,3}(/\\d{0,3})?");
4143

42-
private final int nMaskBits;
43-
4444
private final InetAddress requiredAddress;
4545

46+
private final int nMaskBits;
47+
4648
/**
4749
* Takes a specific IP address or a range specified using the IP/Netmask (e.g.
4850
* 192.168.1.0/24 or 202.24.0.0/14).
@@ -52,33 +54,37 @@ public final class IpAddressMatcher implements RequestMatcher {
5254
public IpAddressMatcher(String ipAddress) {
5355
Assert.hasText(ipAddress, "ipAddress cannot be empty");
5456
assertNotHostName(ipAddress);
57+
58+
String requiredAddress;
59+
int nMaskBits;
5560
if (ipAddress.indexOf('/') > 0) {
56-
String[] addressAndMask = StringUtils.split(ipAddress, "/");
57-
ipAddress = addressAndMask[0];
58-
this.nMaskBits = Integer.parseInt(addressAndMask[1]);
61+
String[] parts = Objects.requireNonNull(StringUtils.split(ipAddress, "/"));
62+
requiredAddress = parts[0];
63+
nMaskBits = Integer.parseInt(parts[1]);
5964
}
6065
else {
61-
this.nMaskBits = -1;
66+
requiredAddress = ipAddress;
67+
nMaskBits = -1;
6268
}
63-
this.requiredAddress = parseAddress(ipAddress);
64-
String finalIpAddress = ipAddress;
69+
this.requiredAddress = parseAddress(requiredAddress);
70+
this.nMaskBits = nMaskBits;
6571
Assert.isTrue(this.requiredAddress.getAddress().length * 8 >= this.nMaskBits, () -> String
66-
.format("IP address %s is too short for bitmask of length %d", finalIpAddress, this.nMaskBits));
72+
.format("IP address %s is too short for bitmask of length %d", requiredAddress, this.nMaskBits));
6773
}
6874

6975
@Override
7076
public boolean matches(HttpServletRequest request) {
7177
return matches(request.getRemoteAddr());
7278
}
7379

74-
public boolean matches(String address) {
80+
public boolean matches(String ipAddress) {
7581
// Do not match null or blank address
76-
if (!StringUtils.hasText(address)) {
82+
if (!StringUtils.hasText(ipAddress)) {
7783
return false;
7884
}
7985

80-
assertNotHostName(address);
81-
InetAddress remoteAddress = parseAddress(address);
86+
assertNotHostName(ipAddress);
87+
InetAddress remoteAddress = parseAddress(ipAddress);
8288
if (!this.requiredAddress.getClass().equals(remoteAddress.getClass())) {
8389
return false;
8490
}
@@ -88,26 +94,31 @@ public boolean matches(String address) {
8894
byte[] remAddr = remoteAddress.getAddress();
8995
byte[] reqAddr = this.requiredAddress.getAddress();
9096
int nMaskFullBytes = this.nMaskBits / 8;
91-
byte finalByte = (byte) (0xFF00 >> (this.nMaskBits & 0x07));
9297
for (int i = 0; i < nMaskFullBytes; i++) {
9398
if (remAddr[i] != reqAddr[i]) {
9499
return false;
95100
}
96101
}
102+
byte finalByte = (byte) (0xFF00 >> (this.nMaskBits & 0x07));
97103
if (finalByte != 0) {
98104
return (remAddr[nMaskFullBytes] & finalByte) == (reqAddr[nMaskFullBytes] & finalByte);
99105
}
100106
return true;
101107
}
102108

103-
private void assertNotHostName(String ipAddress) {
104-
boolean isIpv4 = IPV4.matcher(ipAddress).matches();
105-
if (isIpv4) {
106-
return;
107-
}
108-
String error = "ipAddress " + ipAddress + " doesn't look like an IP Address. Is it a host name?";
109-
Assert.isTrue(ipAddress.charAt(0) == '[' || ipAddress.charAt(0) == ':'
110-
|| (Character.digit(ipAddress.charAt(0), 16) != -1 && ipAddress.contains(":")), error);
109+
private static void assertNotHostName(String ipAddress) {
110+
Assert.isTrue(isIpAddress(ipAddress),
111+
() -> String.format("ipAddress %s doesn't look like an IP Address. Is it a host name?", ipAddress));
112+
}
113+
114+
private static boolean isIpAddress(String ipAddress) {
115+
// @formatter:off
116+
return IPV4.matcher(ipAddress).matches()
117+
|| ipAddress.charAt(0) == '['
118+
|| ipAddress.charAt(0) == ':'
119+
|| Character.digit(ipAddress.charAt(0), 16) != -1
120+
&& ipAddress.indexOf(':') > 0;
121+
// @formatter:on
111122
}
112123

113124
private InetAddress parseAddress(String address) {

0 commit comments

Comments
 (0)