From aeb1c113345241b379ff0809f96b25bf97ddbeb7 Mon Sep 17 00:00:00 2001 From: Ashish Singh Date: Tue, 29 Jan 2019 15:03:18 +0530 Subject: [PATCH] mgr/dashboard: Replace IP address validation with Python standard library functions Instead of self-written validation methods to validate IPv4 and IPv6 addresses. Use Python's standard library functions `ipaddress`. Signed-off-by: Ashish Singh --- ceph.spec.in | 1 + debian/control | 1 + .../mgr/dashboard/services/rgw_client.py | 10 +- src/pybind/mgr/dashboard/tests/test_tools.py | 11 +- src/pybind/mgr/dashboard/tools.py | 113 ++---------------- 5 files changed, 17 insertions(+), 119 deletions(-) diff --git a/ceph.spec.in b/ceph.spec.in index afbe2b695b81..a7cc6575d4e2 100644 --- a/ceph.spec.in +++ b/ceph.spec.in @@ -473,6 +473,7 @@ Group: System/Filesystems Requires: ceph-mgr = %{_epoch_prefix}%{version}-%{release} %if 0%{?fedora} || 0%{?rhel} Requires: python%{_python_buildid}-cherrypy +Requires: python%{_python_buildid}-ipaddress Requires: python%{_python_buildid}-jwt Requires: python%{_python_buildid}-routes Requires: python%{_python_buildid}-werkzeug diff --git a/debian/control b/debian/control index bfb22d83e8d1..2bb5e6fbb90e 100644 --- a/debian/control +++ b/debian/control @@ -208,6 +208,7 @@ Package: ceph-mgr-dashboard Architecture: all Depends: ceph-mgr (= ${binary:Version}), python-cherrypy3, + python-ipaddress, python-jwt, python-openssl, python-bcrypt, diff --git a/src/pybind/mgr/dashboard/services/rgw_client.py b/src/pybind/mgr/dashboard/services/rgw_client.py index 72b6b1d913e8..cb1f229fcee3 100644 --- a/src/pybind/mgr/dashboard/services/rgw_client.py +++ b/src/pybind/mgr/dashboard/services/rgw_client.py @@ -2,11 +2,13 @@ from __future__ import absolute_import import re +import ipaddress from distutils.util import strtobool +import six from ..awsauth import S3Auth from ..settings import Settings, Options from ..rest_client import RestClient, RequestException -from ..tools import build_url, dict_contains_path, is_valid_ip_address +from ..tools import build_url, dict_contains_path from .. import mgr, logger @@ -125,9 +127,11 @@ def _parse_addr(value): # Group 1: [ # Group 2: 2001:db8:85a3::8a2e:370:7334 addr = match.group(3) if match.group(3) else match.group(2) - if not is_valid_ip_address(addr): + try: + ipaddress.ip_address(six.u(addr)) + return addr + except ValueError: raise LookupError('Invalid RGW address \'{}\' found'.format(addr)) - return addr raise LookupError('Failed to determine RGW address') diff --git a/src/pybind/mgr/dashboard/tests/test_tools.py b/src/pybind/mgr/dashboard/tests/test_tools.py index 028ec7087730..7095b7598ab4 100644 --- a/src/pybind/mgr/dashboard/tests/test_tools.py +++ b/src/pybind/mgr/dashboard/tests/test_tools.py @@ -11,8 +11,7 @@ from . import ControllerTestCase from ..services.exception import handle_rados_error from ..controllers import RESTController, ApiController, Controller, \ BaseController, Proxy -from ..tools import is_valid_ipv6_address, dict_contains_path, \ - RequestLoggingTool +from ..tools import dict_contains_path, RequestLoggingTool # pylint: disable=W0613 @@ -172,14 +171,6 @@ class RequestLoggingToolTest(ControllerTestCase): class TestFunctions(unittest.TestCase): - def test_is_valid_ipv6_address(self): - self.assertTrue(is_valid_ipv6_address('::')) - self.assertTrue(is_valid_ipv6_address('::1')) - self.assertFalse(is_valid_ipv6_address('127.0.0.1')) - self.assertFalse(is_valid_ipv6_address('localhost')) - self.assertTrue(is_valid_ipv6_address('1200:0000:AB00:1234:0000:2552:7777:1313')) - self.assertFalse(is_valid_ipv6_address('1200::AB00:1234::2552:7777:1313')) - def test_dict_contains_path(self): x = {'a': {'b': {'c': 'foo'}}} self.assertTrue(dict_contains_path(x, ['a', 'b', 'c'])) diff --git a/src/pybind/mgr/dashboard/tools.py b/src/pybind/mgr/dashboard/tools.py index 7eb23e535b70..f88092750e73 100644 --- a/src/pybind/mgr/dashboard/tools.py +++ b/src/pybind/mgr/dashboard/tools.py @@ -5,6 +5,7 @@ import sys import inspect import json import functools +import ipaddress import collections from datetime import datetime, timedelta @@ -12,7 +13,7 @@ from distutils.util import strtobool import fnmatch import time import threading -import socket +import six from six.moves import urllib import cherrypy @@ -646,110 +647,6 @@ class Task(object): self.lock.release() -def is_valid_ip_address(addr): - """ - Validate the given IPv4 or IPv6 address. - - >>> is_valid_ip_address('2001:0db8::1234') - True - - >>> is_valid_ip_address('192.168.121.1') - True - - >>> is_valid_ip_address('1:::1') - False - - >>> is_valid_ip_address('8.1.0') - False - - >>> is_valid_ip_address('260.1.0.1') - False - - :param addr: - :type addr: str - :return: Returns ``True`` if the IP address is valid, - otherwise ``False``. - :rtype: bool - """ - return is_valid_ipv4_address(addr) or is_valid_ipv6_address(addr) - - -def is_valid_ipv4_address(addr): - """ - Validate the given IPv4 address. - - >>> is_valid_ipv4_address('0.0.0.0') - True - - >>> is_valid_ipv4_address('192.168.121.1') - True - - >>> is_valid_ipv4_address('a.b.c.d') - False - - >>> is_valid_ipv4_address('172.1.0.a') - False - - >>> is_valid_ipv4_address('2001:0db8::1234') - False - - >>> is_valid_ipv4_address(None) - False - - >>> is_valid_ipv4_address(123456) - False - - :param addr: - :type addr: str - :return: Returns ``True`` if the IPv4 address is valid, - otherwise ``False``. - :rtype: bool - """ - try: - socket.inet_pton(socket.AF_INET, addr) - return True - except (socket.error, TypeError): - return False - - -def is_valid_ipv6_address(addr): - """ - Validate the given IPv6 address. - - >>> is_valid_ipv6_address('2001:0db8::1234') - True - - >>> is_valid_ipv6_address('fe80::bc6c:66b0:5af8:f44') - True - - >>> is_valid_ipv6_address('192.168.121.1') - False - - >>> is_valid_ipv6_address('a:x::1') - False - - >>> is_valid_ipv6_address('1200:0000:AB00:1234:O000:2552:7777:1313') - False - - >>> is_valid_ipv6_address(None) - False - - >>> is_valid_ipv6_address(123456) - False - - :param addr: - :type addr: str - :return: Returns ``True`` if the IPv6 address is valid, - otherwise ``False``. - :rtype: bool - """ - try: - socket.inet_pton(socket.AF_INET6, addr) - return True - except (socket.error, TypeError): - return False - - def build_url(host, scheme=None, port=None): """ Build a valid URL. IPv6 addresses specified in host will be enclosed in brackets @@ -772,7 +669,11 @@ def build_url(host, scheme=None, port=None): :type port: int :rtype: str """ - netloc = host if not is_valid_ipv6_address(host) else '[{}]'.format(host) + try: + ipaddress.IPv6Address(six.u(host)) + netloc = '[{}]'.format(host) + except ValueError: + netloc = host if port: netloc += ':{}'.format(port) pr = urllib.parse.ParseResult( -- 2.47.3