Skip to content

Commit 8379d70

Browse files
Merge pull request #653 from skoranda/ipv6_bracket_matching
Fix IPv6 validation for addresses enclosed in brackets
2 parents ad83f81 + 95911d9 commit 8379d70

File tree

2 files changed

+41
-38
lines changed

2 files changed

+41
-38
lines changed

src/saml2/validate.py

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import struct
55
import base64
66
import time
7+
from ipaddress import AddressValueError
8+
from ipaddress import IPv4Address
9+
from ipaddress import IPv6Address
710

811
from saml2 import time_util
912

@@ -112,55 +115,30 @@ def validate_before(not_before, slack):
112115

113116

114117
def valid_address(address):
118+
"""Validate IPv4/IPv6 addresses."""
115119
if not (valid_ipv4(address) or valid_ipv6(address)):
116120
raise NotValid("address")
117121
return True
118122

119123

120124
def valid_ipv4(address):
121-
parts = address.split(".")
122-
if len(parts) != 4:
125+
"""Validate IPv4 addresses."""
126+
try:
127+
IPv4Address(address)
128+
except AddressValueError:
123129
return False
124-
for item in parts:
125-
try:
126-
if not 0 <= int(item) <= 255:
127-
raise NotValid("ipv4")
128-
except ValueError:
129-
return False
130130
return True
131131

132-
#
133-
IPV6_PATTERN = re.compile(r"""
134-
^
135-
\s* # Leading whitespace
136-
(?!.*::.*::) # Only a single wildcard allowed
137-
(?:(?!:)|:(?=:)) # Colon iff it would be part of a wildcard
138-
(?: # Repeat 6 times:
139-
[0-9a-f]{0,4} # A group of at most four hexadecimal digits
140-
(?:(?<=::)|(?<!::):) # Colon unless preceeded by wildcard
141-
){6} #
142-
(?: # Either
143-
[0-9a-f]{0,4} # Another group
144-
(?:(?<=::)|(?<!::):) # Colon unless preceeded by wildcard
145-
[0-9a-f]{0,4} # Last group
146-
(?: (?<=::) # Colon iff preceeded by exacly one colon
147-
| (?<!:) #
148-
| (?<=:) (?<!::) : #
149-
) # OR
150-
| # A v4 address with NO leading zeros
151-
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)
152-
(?: \.
153-
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)
154-
){3}
155-
)
156-
\s* # Trailing whitespace
157-
$
158-
""", re.VERBOSE | re.IGNORECASE | re.DOTALL)
159-
160132

161133
def valid_ipv6(address):
162-
"""Validates IPv6 addresses. """
163-
return IPV6_PATTERN.match(address) is not None
134+
"""Validate IPv6 addresses."""
135+
is_enclosed_in_brackets = address.startswith("[") and address.endswith("]")
136+
address_raw = address[1:-1] if is_enclosed_in_brackets else address
137+
try:
138+
IPv6Address(address_raw)
139+
except AddressValueError:
140+
return False
141+
return True
164142

165143

166144
def valid_boolean(val):

tests/test_13_validate.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from saml2.validate import valid_any_uri
1414
from saml2.validate import NotValid
1515
from saml2.validate import valid_anytype
16+
from saml2.validate import valid_address
1617

1718
from pytest import raises
1819

@@ -120,3 +121,27 @@ def test_valid_anytype():
120121
assert valid_anytype("P1Y2M3DT10H30M")
121122
assert valid_anytype("urn:oasis:names:tc:SAML:2.0:attrname-format:uri")
122123

124+
125+
def test_valid_address():
126+
assert valid_address("130.239.16.3")
127+
assert valid_address("2001:8003:5555:9999:555a:5555:c77:d5c5")
128+
assert valid_address("2001:8003:5555::555a:5555:c77:d5c5")
129+
130+
# See https://tools.ietf.org/html/rfc4038#section-5.1 regarding
131+
# the inclusion of brackets in the ipv6 address below.
132+
assert valid_address("[2001:8003:5555:9999:555a:5555:c77:d5c5]")
133+
134+
with raises(NotValid):
135+
assert valid_address("127.0.0.256")
136+
with raises(NotValid):
137+
assert valid_address("127.0.0.")
138+
with raises(NotValid):
139+
assert valid_address("127.0.0")
140+
with raises(NotValid):
141+
assert valid_address("2001::5555:9999::5555:c77:d5c5]")
142+
with raises(NotValid):
143+
assert valid_address("2001:8003:5555:9999:555a:5555:c77:d5c5]")
144+
with raises(NotValid):
145+
assert valid_address("[2001:8003:5555:9999:555a:5555:c77:d5c5")
146+
with raises(NotValid):
147+
assert valid_address("[[2001:8003:5555:9999:555a:5555:c77:d5c5]")

0 commit comments

Comments
 (0)