def test_shadowing_services(self):
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <service>
              <entry name="tcp-nondup"><protocol><tcp><port>1</port><override><no/></override></tcp></protocol></entry>
              <entry name="tcp-dup"><protocol><tcp><port>2</port><override><no/></override></tcp></protocol></entry>
            </service>
          </shared>
          <devices><entry><device-group><entry name="test_dg">
            <service>
              <entry name="tcp-dup"><protocol><tcp><port>2</port><override><no/></override></tcp></protocol></entry>
            </service>
          </entry></device-group></entry></devices>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        shared_services = pan_config.get_devicegroup_object('Services', 'shared')
        dg_services = pan_config.get_devicegroup_object('Services', 'test_dg')
        profilepackage = self.create_profilepackage(shared_services, dg_services, [], [])

        _, _, validator_function = get_policy_validators()['ShadowingServices']
        results = validator_function(profilepackage)

        self.assertEqual(len(results), 1)
        self.assertEqual(len(results[0].data), 2)
        self.assertEqual(results[0].data[0][0], 'shared')
        self.assertEqual(results[0].data[0][1].get('name'), 'tcp-dup')
        self.assertEqual(results[0].data[1][0], 'test_dg')
        self.assertEqual(results[0].data[1][1].get('name'), 'tcp-dup')
示例#2
0
    def test_badhostname(self, mocked_dns_lookup):
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <pre-rulebase><security><rules>
              <entry name="test_rule">
                <source><member>invalid_fqdn</member></source>
                <destination><member>ignored_fqdn</member></destination>
              </entry>
            </rules></security></pre-rulebase>
            <address>
              <entry name="ignored_ip_netmask"><ip-netmask>127.0.0.1</ip-netmask></entry>
              <entry name="ignored_fqdn"><fqdn>ignored.tld</fqdn></entry>
              <entry name="valid_fqdn"><fqdn>valid.tld</fqdn></entry>
              <entry name="invalid_fqdn"><fqdn>invalid.bad.tld</fqdn></entry>
            </address>
            <address-group>
              <entry name="Sample valid AG"><static><member>valid_fqdn</member></static></entry>
              <entry name="Sample invalid AG"><static><member>invalid_fqdn</member></static></entry>
            </address-group>
          </shared>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        addresses = pan_config.get_devicegroup_object('Addresses', 'shared')
        address_groups = pan_config.get_devicegroup_object('AddressGroups', 'shared')
        rules = pan_config.get_devicegroup_policy('SecurityPreRules', 'shared')
        ignored_dns_prefixes = ["ignored"]
        mocked_dns_lookup.side_effect = ['127.0.0.1', None]
        profilepackage = self.create_profilepackage(addresses, address_groups, rules, ignored_dns_prefixes)

        _, _, validator_function = get_policy_validators()['BadHostname']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].data.get('name'), 'invalid_fqdn')
    def test_with_mandated_profile(self):
        test_xml = """\
        <response status="success"><result><config>
          <devices><entry><device-group><entry name="test_dg">
            <pre-rulebase><security><rules>
              <entry name="first_rule">
                <from><member>src_zone</member></from>
                <to><member>dest_zone</member></to>
                <source><member>ip-127.0.0.2</member></source>
                <destination><member>ip-127.0.0.3</member></destination>
              </entry>
              <entry name="superseding_rule">
                <from><member>src_zone</member></from>
                <to><member>dest_zone</member></to>
                <source><member>ip-127.0.0.2</member></source>
                <destination>
                  <member>ip-127.0.0.3</member>
                  <member>ip-127.0.0.4</member>
                </destination>
              </entry>
            </rules></security></pre-rulebase>
          </entry></device-group></entry></devices>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        rules = pan_config.get_devicegroup_policy('SecurityPreRules',
                                                  'test_dg')

        profilepackage = self.create_profilepackage(rules)
        results = find_superseding_rules(profilepackage)
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].data[0][2], 'first_rule')
        self.assertEqual(results[0].data[1][2], 'superseding_rule')
    def test_shadowing_servicegroups(self):
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <service-group>
              <entry name="uniquegroup1"><members><member>mem1</member><member>mem2</member></members></entry>
              <entry name="dupgroup1"><members><member>mem1</member><member>mem2</member></members></entry>
            </service-group>
          </shared>
          <devices><entry><device-group><entry name="test_dg">
            <service-group>
              <entry name="dupgroup1"><members><member>mem1</member><member>mem2</member></members></entry>
              <entry name="uniquegroup2"><members><member>mem1</member><member>mem2</member></members></entry>
            </service-group>
          </entry></device-group></entry></devices>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        shared_service_groups = pan_config.get_devicegroup_object('ServiceGroups', 'shared')
        dg_service_groups = pan_config.get_devicegroup_object('ServiceGroups', 'test_dg')

        profilepackage = self.create_profilepackage([], [], shared_service_groups, dg_service_groups)

        _, _, validator_function = get_policy_validators()['ShadowingServiceGroups']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 1)
        self.assertEqual(len(results[0].data), 2)
        self.assertEqual(results[0].data[0][0], 'shared')
        self.assertEqual(results[0].data[0][1].get('name'), 'dupgroup1')
        self.assertEqual(results[0].data[1][0], 'test_dg')
        self.assertEqual(results[0].data[1][1].get('name'), 'dupgroup1')
    def test_misleading_services(self):
        test_xml = """\
        <response status="success"><result><config><shared><service>
            <entry name="valid-tcp-123"><protocol><tcp><port>123</port></tcp></protocol></entry>
            <entry name="valid-tcp-1234"><protocol><tcp><port>123</port></tcp></protocol></entry>
            <entry name="valid-udp-123"><protocol><udp><port>123</port></udp></protocol></entry>
            <entry name="valid-udp-1234"><protocol><udp><port>123</port></udp></protocol></entry>
            <entry name="invalid-protocol-tcp-123"><protocol><udp><port>123</port></udp></protocol></entry>
            <entry name="invalid-protocol-udp-1234"><protocol><tcp><port>123</port></tcp></protocol></entry>
            <entry name="invalid-port-1233"><protocol><udp><port>1234</port></udp></protocol></entry>
            <entry name="invalid-port-and-protocol-tcp-123"><protocol><udp><port>1234</port></udp></protocol></entry>
        </service></shared></config></result></response>
        """
        pan_config = PanConfig(test_xml)
        services = pan_config.get_devicegroup_object('Services', 'shared')
        profilepackage = self.create_profilepackage(services)

        _, _, validator_function = get_policy_validators(
        )['MisleadingServices']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 4)
        self.assertEqual(results[0].data.get('name'),
                         'invalid-protocol-tcp-123')
        self.assertEqual(results[1].data.get('name'),
                         'invalid-protocol-udp-1234')
        self.assertEqual(results[2].data.get('name'), 'invalid-port-1233')
        self.assertEqual(results[3].data.get('name'),
                         'invalid-port-and-protocol-tcp-123')
    def create_profilepackage(allowed_group_profile, pan_config):
        device_groups = ['test_dg']
        rules = pan_config.get_devicegroup_policy('SecurityPreRules',
                                                  'test_dg')
        devicegroup_exclusive_objects = {
            'test_dg': {
                'SecurityPreRules': rules,
                'SecurityPostRules': []
            }
        }

        settings = ConfigurationSettings().get_config()
        settings['Allowed Group Profiles'] = allowed_group_profile

        profilepackage = ProfilePackage(
            api_key='',
            pan_config=PanConfig('<_/>'),
            settings=settings,
            device_group_hierarchy_children={},
            device_group_hierarchy_parent={},
            device_groups_and_firewalls={},
            device_groups=device_groups,
            devicegroup_objects={},
            devicegroup_exclusive_objects=devicegroup_exclusive_objects,
            rule_limit_enabled=False,
            no_api=False)
        return profilepackage
 def test_equivalent_addressgroups(self):
     test_xml = """\
     <response status="success"><result><config>
       <shared>
         <address>
           <entry name="unique_netmask1"><ip-netmask>127.0.0.2/32</ip-netmask></entry>
           <entry name="unique_netmask2"><ip-netmask>127.0.0.1/32</ip-netmask></entry>
         </address>
         <address-group>
           <entry name="address_group1"><static><member>unique_netmask1</member><member>unique_netmask2</member></static></entry>
           <entry name="address_group2"><static><member>unique_netmask2</member><member>unique_netmask1</member></static></entry>
         </address-group>
       </shared>
     </config></result></response>
     """
     pan_config = PanConfig(test_xml)
     profilepackage = self.create_profilepackage('AddressGroups',
                                                 pan_config)
     _, _, validator_function = get_policy_validators(
     )['EquivalentAddressGroups']
     results = validator_function(profilepackage)
     self.assertEqual(len(results), 1)
     self.assertEqual(len(results[0].data), 2)
     self.assertEqual(results[0].data[0][0], 'shared')
     self.assertEqual(results[0].data[0][1].get('name'), 'address_group1')
     self.assertEqual(results[0].data[1][0], 'shared')
     self.assertEqual(results[0].data[1][1].get('name'), 'address_group2')
    def test_equivalent_servicegroups(self):
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <service>
              <entry name="tcp-1"><protocol><tcp><port>1</port><override><no/></override></tcp></protocol></entry>
              <entry name="tcp-2"><protocol><tcp><port>2</port><override><no/></override></tcp></protocol></entry>
            </service>
            <service-group>
              <entry name="dup1"><members><member>tcp-1</member><member>tcp-2</member></members></entry>
              <entry name="dup2"><members><member>tcp-2</member><member>tcp-1</member></members></entry>
            </service-group>
          </shared>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        profilepackage = self.create_profilepackage('ServiceGroups',
                                                    pan_config)

        _, _, validator_function = get_policy_validators(
        )['EquivalentServiceGroups']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 1)
        self.assertEqual(len(results[0].data), 2)
        self.assertEqual(results[0].data[0][0], 'shared')
        self.assertEqual(results[0].data[0][1].get('name'), 'dup1')
        self.assertEqual(results[0].data[1][0], 'shared')
        self.assertEqual(results[0].data[1][1].get('name'), 'dup2')
    def test_misleading_services(self):
        test_xml = """\
        <response status="success"><result><config><shared><service>
            <entry name="prefix-tcp-123"><protocol><tcp><port>123</port></tcp></protocol></entry>
            <entry name="prefix-tcp-1234"><protocol><tcp><port>123</port></tcp></protocol></entry>
            <entry name="prefix-udp-123"><protocol><udp><port>123</port></udp></protocol></entry>
            <entry name="prefix-udp-1234"><protocol><udp><port>123</port></udp></protocol></entry>
            <entry name="missing-tcp-123"><protocol><udp><port>1234</port></udp></protocol></entry>
        </service></shared></config></result></response>
        """
        pan_config = PanConfig(test_xml)
        service_name_format = 'prefix-{transport}-{port}'
        profilepackage = self.create_profilepackage(pan_config,
                                                    service_name_format)

        _, _, validator_function = get_policy_validators(
        )['UnconventionallyNamedServices']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 3)
        self.assertEqual(results[0].data[0].get('name'), 'prefix-tcp-1234')
        self.assertEqual(results[0].data[1], 'prefix-tcp-123')
        self.assertEqual(results[1].data[0].get('name'), 'prefix-udp-1234')
        self.assertEqual(results[1].data[1], 'prefix-udp-123')
        self.assertEqual(results[2].data[0].get('name'), 'missing-tcp-123')
        self.assertEqual(results[2].data[1], 'prefix-udp-1234')
    def create_profilepackage(rules, addresses):
        device_groups = ['test_dg']
        devicegroup_objects = {'test_dg': collections.defaultdict(list)}
        devicegroup_objects['test_dg']['Addresses'] = addresses
        devicegroup_objects['test_dg']['all_active_child_firewalls'] = [
            "fake_firewall"
        ]
        devicegroup_exclusive_objects = {
            'test_dg': collections.defaultdict(list)
        }
        devicegroup_exclusive_objects["test_dg"]['SecurityPreRules'] = rules

        profilepackage = ProfilePackage(
            api_key='',
            pan_config=PanConfig('<_/>'),
            settings=ConfigurationSettings().get_config(),
            device_group_hierarchy_children={},
            device_group_hierarchy_parent={},
            device_groups_and_firewalls={},
            device_groups=device_groups,
            devicegroup_objects=devicegroup_objects,
            devicegroup_exclusive_objects=devicegroup_exclusive_objects,
            rule_limit_enabled=False,
            no_api=False)
        return profilepackage
示例#11
0
    def test_with_mandated_profile(self):
        test_xml = """\
        <response status="success"><result><config>
          <devices><entry><device-group><entry name="test_dg">
            <pre-rulebase><security><rules>
              <entry name="same_zone_rule">
                <service>
                  <member>tcp-123</member>
                  <member>myservicegroup</member>
                </service>
              </entry>
            </rules></security></pre-rulebase>
            <service><entry name="tcp-123"><protocol><tcp><port>123</port></tcp></protocol></entry></service>
            <service-group><entry name="myservicegroup"><members><member>tcp-123</member></members></entry></service-group>
          </entry></device-group></entry></devices>
          <readonly><devices><entry name="localhost.localdomain"><device-group>
            <entry name="test_dg"><id>11</id></entry>
          </device-group></entry></devices></readonly>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)

        profilepackage = self.create_profilepackage(pan_config)
        _, _, validator_function = get_policy_validators()['RedundantRuleServices']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 1)
        ruletype, rule_entry, members_to_remove = results[0].data
        self.assertEqual(ruletype, 'SecurityPreRules')
        self.assertEqual(rule_entry.get('name'), 'same_zone_rule')
        self.assertEqual(members_to_remove, [('tcp-123', 'myservicegroup')])
    def test_IPWithResolvingFQDN(self, mocked_dns_lookup):
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <pre-rulebase><security><rules>
              <entry name="test_rule">
                <source><member>invalid_fqdn</member></source>
                <destination><member>ignored_fqdn</member></destination>
              </entry>
            </rules></security></pre-rulebase>
            <address>
              <entry name="redundant_ip"><ip-netmask>127.0.0.1/32</ip-netmask></entry>
              <entry name="valid_fqdn"><fqdn>valid.tld</fqdn></entry>
              <entry name="invalid_fqdn"><fqdn>invalid.bad.tld</fqdn></entry>
            </address>
          </shared>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        mocked_dns_lookup.side_effect = [('valid.tld', [], ["127.0.0.1"]),
                                         (None, [], [])]
        profilepackage = self.create_profilepackage(pan_config)

        _, _, validator_function = get_policy_validators(
        )['IPWithResolvingFQDN']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].data[0].get('name'), 'redundant_ip')
        self.assertEqual(results[0].data[1], 'valid.tld')
    def create_profilepackage(shared_addresses, shared_addressgroups,
                              shared_securityprerules, shared_natprerules,
                              dg_addresses, dg_securityprerules):
        device_groups = ["shared"]
        devicegroup_objects = {
            "shared": collections.defaultdict(list),
            "test_dg": collections.defaultdict(list)
        }
        devicegroup_objects['shared']['all_child_device_groups'] = [
            "shared", "test_dg"
        ]
        devicegroup_objects["shared"]['Addresses'] = shared_addresses
        devicegroup_objects["shared"]['AddressGroups'] = shared_addressgroups
        devicegroup_objects["shared"][
            'SecurityPreRules'] = shared_securityprerules
        devicegroup_objects["shared"]['NATPreRules'] = shared_natprerules
        devicegroup_objects["test_dg"]['SecurityPreRules'] = dg_addresses
        devicegroup_objects["test_dg"]['NATPreRules'] = dg_securityprerules

        profilepackage = ProfilePackage(
            api_key='',
            pan_config=PanConfig('<_/>'),
            settings=ConfigurationSettings().get_config(),
            device_group_hierarchy_children={},
            device_group_hierarchy_parent={},
            device_groups_and_firewalls={},
            device_groups=device_groups,
            devicegroup_objects=devicegroup_objects,
            devicegroup_exclusive_objects={},
            rule_limit_enabled=False,
            no_api=False)
        return profilepackage
    def test_unusedaddresses(self):
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <profile-group>
              <entry name="used_group1"></entry>
              <entry name="used_group2"></entry>
              <entry name="unused_group3"></entry>
            </profile-group>
            <pre-rulebase>
              <security><rules>
                <entry name="shared_rule1"><profile-setting><group><member>used_group1</member></group></profile-setting></entry>
              </rules></security>
            </pre-rulebase>
          </shared>
          <devices><entry><device-group><entry name="test_dg">
            <pre-rulebase>
              <security><rules>
                <entry name="dg_rule2"><profile-setting><group><member>used_group2</member></group></profile-setting></entry>
              </rules></security>
            </pre-rulebase>
          </entry></device-group></entry></devices>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        profilepackage = self.create_profilepackage(pan_config)

        _, _, validator_function = get_policy_validators(
        )['UnusedSecurityProfileGroups']
        results = validator_function(profilepackage)

        self.assertEqual(len(results), 1)
        self.assertEqual(len(results[0].data), 1)
        self.assertEqual(results[0].data[0].get('name'), 'unused_group3')
        self.assertEqual(results[0].device_group, 'shared')
示例#15
0
    def test_consolidatable_addresses(self):
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <address>
              <entry name="unique_netmask1"><ip-netmask>127.0.0.1/32</ip-netmask></entry>
              <entry name="unique_netmask2"><ip-netmask>127.0.0.2/32</ip-netmask></entry>
              <entry name="duplicate_netmask2"><ip-netmask>127.0.0.2/32</ip-netmask></entry>
            </address>
            <address-group>
              <entry name="address_group1"><static><member>unique_netmask1</member><member>unique_netmask2</member></static></entry>
              <entry name="address_group2"><static><member>unique_netmask2</member><member>unique_netmask1</member></static></entry>
              <entry name="address_group3"><static><member>duplicate_netmask2</member><member>unique_netmask1</member></static></entry>
            </address-group>
          </shared>
          <devices><entry><device-group><entry name="test_dg">
            <pre-rulebase><security><rules>
              <entry name="rule1">
                <from><member>src_zone</member></from>
                <to><member>dest_zone</member></to>
                <source><member>unique_netmask1</member></source>
                <destination><member>unique_netmask2</member></destination>
                <service><member>tcp2-dup1</member></service>
              </entry>
              <entry name="rule2">
                <from><member>src_zone</member></from>
                <to><member>dest_zone</member></to>
                <source><member>unique_netmask1</member></source>
                <destination><member>unique_netmask2</member></destination>
                <service><member>tcp2-dup1</member></service>
              </entry>
              <entry name="rule3">
                <from><member>src_zone</member></from>
                <to><member>dest_zone</member></to>
                <source><member>unique_netmask1</member></source>
                <destination><member>duplicate_netmask2</member></destination>
                <service><member>tcp2-dup2</member></service>
              </entry>
            </rules></security></pre-rulebase>
          </entry></device-group></entry></devices>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        profilepackage = self.create_profilepackage(pan_config)

        _, _, validator_function = get_policy_validators(
        )['FindConsolidatableAddresses']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 2)
        self.assertEqual(len(results[0].data), 2)
        self.assertEqual(results[0].data[0].get('name'), 'address_group3')
        self.assertEqual(results[0].data[1]['static']['member'][0],
                         'unique_netmask2')
        self.assertEqual(len(results[1].data), 2)
        self.assertEqual(results[1].data[0].get('name'), 'rule3')
        self.assertEqual(results[1].data[1]['destination']['member'],
                         'unique_netmask2')
    def test_missingzones(self, get_firewall_zone):
        test_xml = """\
        <response status="success"><result><config>
          <devices><entry><device-group><entry name="test_dg">
            <pre-rulebase><security><rules>
              <entry name="missing_zone_rule">
                <from>
                  <member>src_zone</member>
                </from>
                <to>
                  <member>dest_zone</member>
                </to>
                <source>
                  <member>ip-127.0.0.2</member>
                </source>
                <destination>
                  <member>ip-127.0.0.3</member>
                  <member>ip-127.0.0.4</member>
                </destination>
              </entry>
            </rules></security></pre-rulebase>
            <address>
              <entry name="ip-127.0.0.2"><ip-netmask>127.0.0.2</ip-netmask></entry>
              <entry name="ip-127.0.0.3"><ip-netmask>127.0.0.3</ip-netmask></entry>
              <entry name="ip-127.0.0.4"><ip-netmask>127.0.0.4</ip-netmask></entry>
            </address>
          </entry></device-group></entry></devices>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        rules = pan_config.get_devicegroup_policy('SecurityPreRules',
                                                  'test_dg')
        addresses = pan_config.get_devicegroup_object('Addresses', 'test_dg')

        profilepackage = self.create_profilepackage(rules, addresses)
        get_firewall_zone.side_effect = [
            'src_zone', 'dest_zone', "missing_zone"
        ]
        _, _, validator_function = get_policy_validators()['MissingZones']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].data.get('name'), 'missing_zone_rule')
    def test_shadowing_addresses_and_groups(self):
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <address>
              <entry name="dup_shared_address_shared_ag_dg_address"/>
            </address>
            <address-group>
              <entry name="dup_shared_address_shared_ag_dg_address"/>
            </address-group>
          </shared>
          <devices><entry><device-group><entry name="test_dg">
            <address>
              <entry name="dup_shared_address_shared_ag_dg_address"/>
            </address>
            <address-group>
            </address-group>
          </entry></device-group></entry></devices>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        shared_addresses = pan_config.get_devicegroup_object(
            'Addresses', 'shared')
        dg_addesses = pan_config.get_devicegroup_object('Addresses', 'test_dg')
        shared_addressgroups = pan_config.get_devicegroup_object(
            'AddressGroups', 'shared')
        dg_addessgroups = pan_config.get_devicegroup_object(
            'AddressGroups', 'test_dg')
        profilepackage = self.create_profilepackage(shared_addresses,
                                                    dg_addesses,
                                                    shared_addressgroups,
                                                    dg_addessgroups)

        _, _, validator_function = get_policy_validators(
        )['ShadowingAddressesAndGroups']
        results = validator_function(profilepackage)

        self.assertEqual(len(results), 2)
        self.assertEqual(len(results[0].data), 2)
        self.assertEqual(results[0].data[0][0], 'shared')
        self.assertEqual(results[0].data[0][1], 'AddressGroups')
        self.assertEqual(results[0].data[0][2].get('name'),
                         'dup_shared_address_shared_ag_dg_address')
        self.assertEqual(results[0].data[1][0], 'shared')
        self.assertEqual(results[0].data[1][1], 'Addresses')
        self.assertEqual(results[0].data[1][2].get('name'),
                         'dup_shared_address_shared_ag_dg_address')
        self.assertEqual(len(results[1].data), 3)
        self.assertEqual(results[1].data[0][0], 'test_dg')
        self.assertEqual(results[1].data[0][1], 'Addresses')
        self.assertEqual(results[1].data[0][2].get('name'),
                         'dup_shared_address_shared_ag_dg_address')
        self.assertEqual(results[1].data[1][0], 'shared')
        self.assertEqual(results[1].data[1][1], 'Addresses')
        self.assertEqual(results[1].data[1][2].get('name'),
                         'dup_shared_address_shared_ag_dg_address')
        self.assertEqual(results[1].data[2][0], 'shared')
        self.assertEqual(results[1].data[2][1], 'AddressGroups')
        self.assertEqual(results[1].data[2][2].get('name'),
                         'dup_shared_address_shared_ag_dg_address')
    def test_similar_shared_address_and_dg_addressgroups(self):
        # SimilarAddressesAndGroups previously detected
        # duplicates across device groups. This test is
        # being kept to ensure behavior is as expected.
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <address-group>
              <entry name="SHARED_address_and_dg_addressgroup"/>
            </address-group>
          </shared>
          <devices><entry><device-group><entry name="test_dg">
            <address>
              <entry name="shared_address_and_DG_addressgroup"/>
            </address>
          </entry></device-group></entry></devices>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        shared_addresses = pan_config.get_devicegroup_object(
            'Addresses', 'shared')
        dg_addesses = pan_config.get_devicegroup_object('Addresses', 'test_dg')
        shared_addressgroups = pan_config.get_devicegroup_object(
            'AddressGroups', 'shared')
        dg_addessgroups = pan_config.get_devicegroup_object(
            'AddressGroups', 'test_dg')
        profilepackage = self.create_profilepackage(shared_addresses,
                                                    dg_addesses,
                                                    shared_addressgroups,
                                                    dg_addessgroups)

        _, _, validator_function = get_policy_validators(
        )['SimilarAddressesAndGroups']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 0)
    def test_replaceableaddresses(self):
        test_xml = """\
        <response status="success"><result><config>
          <devices><entry><device-group><entry name="test_dg">
            <pre-rulebase><security><rules>
              <entry name="sservices_can_be_group">
                <source>
                  <member>ip-127.0.0.1</member>
                  <member>ip-127.0.0.2</member>
                </source>
                <destination>
                  <member>ip-127.0.0.3</member>
                </destination>
                <service>
                  <member>tcp-123</member>
                  <member>tcp-456</member>
                </service>
              </entry>
            </rules></security></pre-rulebase>
            <address>
              <entry name="ip-127.0.0.1"><ip-netmask>127.0.0.1</ip-netmask></entry>
              <entry name="ip-127.0.0.2"><ip-netmask>127.0.0.2</ip-netmask></entry>
              <entry name="ip-127.0.0.3"><ip-netmask>127.0.0.3</ip-netmask></entry>
            </address>
            <address-group>
              <entry name="address_addressgroup1"><static><member>ip-127.0.0.1</member><member>ip-127.0.0.2</member></static></entry>
            </address-group>
            <service>
              <entry name="tcp-123"><protocol><tcp><port>123</port></tcp></protocol></entry>
              <entry name="tcp-456"><protocol><tcp><port>456</port></tcp></protocol></entry>
            </service>
            <service-group><entry name="myservicegroup"><members><member>tcp-123</member><member>tcp-456</member></members></entry></service-group>
          </entry></device-group></entry></devices>
          <readonly><devices><entry name="localhost.localdomain"><device-group>
            <entry name="test_dg"><id>11</id></entry>
          </device-group></entry></devices></readonly>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        profilepackage = self.create_profilepackage(pan_config)

        _, _, validator_function = get_policy_validators()['ServicesShouldBeGroups']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 1)
        self.assertEqual(len(results[0].data), 3)
        self.assertEqual(results[0].data[0], 'SecurityPreRules')
        self.assertEqual(results[0].data[1].get('name'), 'sservices_can_be_group')
        self.assertEqual(results[0].data[2], "myservicegroup")
        self.assertEqual(results[0].device_group, 'test_dg')
    def test_misleading_addresses(self):
        test_xml = """\
        <response status="success"><result><config><shared><address>
            <entry name="valid_ip_127.0.0.1"><ip-netmask>127.0.0.1</ip-netmask></entry>
            <entry name="invalid_ip_127.0.0.2"><ip-netmask>127.0.0.1</ip-netmask></entry>
            <entry name="valid_range_127.0.0.1"><ip-range>127.0.0.1-127.0.0.255</ip-range></entry>
            <entry name="invalid_range_128.0.0.1"><ip-range>127.0.0.1-127.0.0.255</ip-range></entry>
            <entry name="valid_fqdn_valid.tld"><fqdn>valid.tld</fqdn></entry>
            <entry name="invalid_fqdn_invalid.tld"><fqdn>missing.invalid.tld</fqdn></entry>
        </address></shared></config></result></response>
        """
        pan_config = PanConfig(test_xml)
        addresses = pan_config.get_devicegroup_object('Addresses', 'shared')
        profilepackage = self.create_profilepackage(addresses)

        _, _, validator_function = get_policy_validators(
        )['MisleadingAddresses']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 3)
        self.assertEqual(results[0].data.get('name'), 'invalid_ip_127.0.0.2')
        self.assertEqual(results[1].data.get('name'),
                         'invalid_range_128.0.0.1')
        self.assertEqual(results[2].data.get('name'),
                         'invalid_fqdn_invalid.tld')
    def test_badhostname(self, mocked_fqdn_lookup):
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <address>
              <entry name="ignored_missing_fqdn"><fqdn>ignored_missing</fqdn></entry>
              <entry name="missing_fqdn"><fqdn>missing</fqdn></entry>
              <entry name="valid_fqdn"><fqdn>valid.tld</fqdn></entry>
            </address>
          </shared>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        addresses = pan_config.get_devicegroup_object('Addresses', 'shared')
        ignored_dns_prefixes = ["ignored"]
        mocked_fqdn_lookup.side_effect = ['missing.tld']
        profilepackage = self.create_profilepackage(addresses,
                                                    ignored_dns_prefixes)

        _, _, validator_function = get_policy_validators()['UnqualifiedFQDN']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].data[0].get('name'), 'missing_fqdn')
        self.assertEqual(results[0].data[1], 'missing.tld')
    def create_profilepackage(services):
        device_groups = ["shared"]
        devicegroup_objects = {"shared": {}}
        devicegroup_objects["shared"]['Services'] = services

        profilepackage = ProfilePackage(
            api_key='',
            pan_config=PanConfig('<_/>'),
            settings=ConfigurationSettings().get_config(),
            device_group_hierarchy_children={},
            device_group_hierarchy_parent={},
            device_groups_and_firewalls={},
            device_groups=device_groups,
            devicegroup_objects=devicegroup_objects,
            devicegroup_exclusive_objects=[],
            rule_limit_enabled=False,
            no_api=False)
        return profilepackage
 def test_equivalent_addresses(self):
     test_xml = """\
     <response status="success"><result><config>
       <shared>
         <address>
           <entry name="unique_netmask"><ip-netmask>ignored.tld</ip-netmask></entry>
           <entry name="dupe_netmask1"><ip-netmask>127.0.0.1</ip-netmask></entry>
           <entry name="dupe_netmask2"><ip-netmask>127.0.0.1/32</ip-netmask></entry>
           <entry name="dup_fqdn1"><fqdn>dupfqdn.tld</fqdn></entry>
           <entry name="dup_fqdn2"><fqdn>dupfqdn.tld</fqdn></entry>
         </address>
       </shared>
       <devices><entry><device-group><entry name="test_dg">
         <address>
           <entry name="unique_fqdn"><ip-netmask>unique.tld</ip-netmask></entry>
           <entry name="dup_fqdn3"><fqdn>dupfqdn.tld</fqdn></entry>
         </address>
       </entry></device-group></entry></devices>
     </config></result></response>
     """
     pan_config = PanConfig(test_xml)
     profilepackage = self.create_profilepackage('Addresses', pan_config)
     _, _, validator_function = get_policy_validators(
     )['EquivalentAddresses']
     results = validator_function(profilepackage)
     self.assertEqual(len(results), 3)
     self.assertEqual(len(results[0].data), 2)
     self.assertEqual(results[0].data[0][0], 'shared')
     self.assertEqual(results[0].data[0][1].get('name'), 'dup_fqdn1')
     self.assertEqual(results[0].data[1][0], 'shared')
     self.assertEqual(results[0].data[1][1].get('name'), 'dup_fqdn2')
     self.assertEqual(len(results[1].data), 2)
     self.assertEqual(results[1].data[0][0], 'shared')
     self.assertEqual(results[1].data[0][1].get('name'), 'dupe_netmask1')
     self.assertEqual(results[1].data[1][0], 'shared')
     self.assertEqual(results[1].data[1][1].get('name'), 'dupe_netmask2')
     self.assertEqual(len(results[2].data), 3)
     self.assertEqual(results[2].data[0][0], 'shared')
     self.assertEqual(results[2].data[0][1].get('name'), 'dup_fqdn1')
     self.assertEqual(results[2].data[1][0], 'shared')
     self.assertEqual(results[2].data[1][1].get('name'), 'dup_fqdn2')
     self.assertEqual(results[2].data[2][0], 'test_dg')
     self.assertEqual(results[2].data[2][1].get('name'), 'dup_fqdn3')
    def test_similar_servicegroups(self):
        test_xml = """\
        <response status="success"><result><config>
          <shared>
            <service-group>
              <entry name="shared_servicegroup1"/>
              <entry name="SHARED_servicegroup1"/>
            </service-group>
          </shared>
          <devices><entry><device-group><entry name="test_dg">
            <service-group>
              <entry name="dg_servicegroup1"/>
              <entry name="DG_servicegroup1"/>
            </service-group>
          </entry></device-group></entry></devices>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)
        shared_services = pan_config.get_devicegroup_object(
            'Services', 'shared')
        dg_services = pan_config.get_devicegroup_object('Services', 'test_dg')
        shared_servicegroups = pan_config.get_devicegroup_object(
            'ServiceGroups', 'shared')
        dg_servicegroups = pan_config.get_devicegroup_object(
            'ServiceGroups', 'test_dg')
        profilepackage = self.create_profilepackage(shared_services,
                                                    dg_services,
                                                    shared_servicegroups,
                                                    dg_servicegroups)

        _, _, validator_function = get_policy_validators(
        )['SimilarServicesAndGroups']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 2)
        self.assertEqual(len(results[0].data), 2)
        self.assertEqual(results[0].data[0][0], 'shared')
        self.assertEqual(results[0].data[0][1], 'ServiceGroups')
        self.assertEqual(results[0].data[0][2].get('name'),
                         'shared_servicegroup1')
        self.assertEqual(results[0].data[1][0], 'shared')
        self.assertEqual(results[0].data[1][1], 'ServiceGroups')
        self.assertEqual(results[0].data[1][2].get('name'),
                         'SHARED_servicegroup1')
        self.assertEqual(len(results[1].data), 2)
        self.assertEqual(results[1].data[0][0], 'test_dg')
        self.assertEqual(results[1].data[0][1], 'ServiceGroups')
        self.assertEqual(results[1].data[0][2].get('name'), 'dg_servicegroup1')
        self.assertEqual(results[1].data[1][0], 'test_dg')
        self.assertEqual(results[1].data[1][1], 'ServiceGroups')
        self.assertEqual(results[1].data[1][2].get('name'), 'DG_servicegroup1')
    def test_with_mandated_profile(self):
        test_xml = """\
        <response status="success"><result><config>
          <devices><entry><device-group><entry name="test_dg">
            <pre-rulebase><security><rules>
              <entry name="same_zone_rule">
                <source>
                  <member>address_addressgroup1</member>
                  <member>ip-127.0.0.2</member>
                </source>
                <destination>
                  <member>ip-127.0.0.3</member>
                </destination>
              </entry>
            </rules></security></pre-rulebase>
            <address>
              <entry name="ip-127.0.0.2"><ip-netmask>127.0.0.2</ip-netmask></entry>
              <entry name="ip-127.0.0.3"><ip-netmask>127.0.0.3</ip-netmask></entry>
            </address>
            <address-group>
              <entry name="address_addressgroup1"><static><member>ip-127.0.0.2</member></static></entry>
            </address-group>
          </entry></device-group></entry></devices>
          <readonly><devices><entry name="localhost.localdomain"><device-group>
            <entry name="test_dg"><id>11</id></entry>
          </device-group></entry></devices></readonly>
        </config></result></response>
        """
        pan_config = PanConfig(test_xml)

        profilepackage = self.create_profilepackage(pan_config)
        _, _, validator_function = get_policy_validators()['RedundantRuleAddresses']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 1)
        ruletype, rule_entry, members_to_remove = results[0].data
        self.assertEqual(ruletype, 'SecurityPreRules')
        self.assertEqual(rule_entry.get('name'), 'same_zone_rule')
        self.assertEqual(list(members_to_remove.keys()), ['source'])
        self.assertEqual(len(members_to_remove['source']), 1)
        member, containing = members_to_remove['source'][0]
        self.assertEqual(member, 'ip-127.0.0.2')
        self.assertEqual(containing, 'address_addressgroup1')
    def create_profilepackage(addresses, ignored_dns_prefixes):
        device_groups = ["shared"]
        devicegroup_objects = {"shared": {}}
        devicegroup_objects["shared"]['Addresses'] = addresses
        settings = ConfigurationSettings().get_config()
        settings['Ignored DNS Prefixes'] = ",".join(ignored_dns_prefixes)

        profilepackage = ProfilePackage(
            api_key='',
            pan_config=PanConfig('<_/>'),
            settings=settings,
            device_group_hierarchy_children={},
            device_group_hierarchy_parent={},
            device_groups_and_firewalls={},
            device_groups=device_groups,
            devicegroup_objects=devicegroup_objects,
            devicegroup_exclusive_objects={},
            rule_limit_enabled=False,
            no_api=False)
        return profilepackage
 def test_without_mandated_logsetting(self):
     test_xml = """\
     <response status="success"><result><config>
       <devices><entry><device-group><entry name="test_dg">
         <pre-rulebase><security><rules>
           <entry name="disabled_rule"><disabled>yes</disabled></entry>
           <entry name="missing_log-setting"><disabled>no</disabled></entry>
           <entry name="correct_log-setting"><log-setting>correct</log-setting></entry>
           <entry name="wrong_log-setting"><log-setting>wrong</log-setting></entry>
         </rules></security></pre-rulebase>
       </entry></device-group></entry></devices>
     </config></result></response>
     """
     mandated_log_profile = None
     pan_config = PanConfig(test_xml)
     profilepackage = self.create_profilepackage(pan_config,
                                                 mandated_log_profile)
     _, _, validator_function = get_policy_validators()['BadLogSetting']
     results = validator_function(profilepackage)
     self.assertEqual(len(results), 0)
    def create_profilepackage(shared_addresses, dg_addresses,
                              shared_address_groups, dg_address_groups):
        device_groups = ["shared", "test_dg"]
        device_group_hierarchy_parent = {"test_dg": "shared"}
        devicegroup_objects = {"shared": {}, "test_dg": {}}
        devicegroup_objects["shared"]['Addresses'] = shared_addresses
        devicegroup_objects["test_dg"]['Addresses'] = dg_addresses
        devicegroup_objects["shared"]['AddressGroups'] = shared_address_groups
        devicegroup_objects["test_dg"]['AddressGroups'] = dg_address_groups

        profilepackage = ProfilePackage(
            api_key='',
            pan_config=PanConfig('<_/>'),
            settings=ConfigurationSettings().get_config(),
            device_group_hierarchy_children={},
            device_group_hierarchy_parent=device_group_hierarchy_parent,
            device_groups_and_firewalls={},
            device_groups=device_groups,
            devicegroup_objects=devicegroup_objects,
            devicegroup_exclusive_objects={},
            rule_limit_enabled=False,
            no_api=False)
        return profilepackage
    def test_with_mandated_profile(self):
        test_xml = """\
        <response status="success"><result><config>
          <devices><entry><device-group><entry name="test_dg">
            <pre-rulebase><security><rules>
              <entry name="disabled_rule"><disabled>yes</disabled></entry>
              <entry name="missing_gp"></entry>
              <entry name="correct_gp"><profile-setting><group><member>correct</member></group></profile-setting></entry>
              <entry name="wrong_gp"><profile-setting><group><member>wrong</member></group></profile-setting></entry>
            </rules></security></pre-rulebase>
          </entry></device-group></entry></devices>
        </config></result></response>
        """
        allowed_group_profile = 'correct'
        pan_config = PanConfig(test_xml)
        profilepackage = self.create_profilepackage(allowed_group_profile,
                                                    pan_config)

        _, _, validator_function = get_policy_validators()['BadGroupProfile']
        results = validator_function(profilepackage)
        self.assertEqual(len(results), 2)
        self.assertEqual(results[0].data.get('name'), 'missing_gp')
        self.assertEqual(results[1].data.get('name'), 'wrong_gp')
def load_config_package(configuration_settings, api_key, device_group, limit, no_api, xml_file=None):
    if xml_file:
        # The list of firewalls are not available from the API, so
        # these variables will remain empty
        logger.debug(f"Loading configuration from XML file: {xml_file}")
        with open(xml_file, encoding='utf-8') as fh:
            xml_config = fh.read()
        pan_config = PanConfig(xml_config, True)
        device_groups_and_firewalls = collections.defaultdict(list)
        active_firewalls_per_devicegroup = collections.defaultdict(list)
    else:
        # Load the XML configuration and list of firewalls via API requests
        panorama = configuration_settings.get('panorama')
        xml_config = pan_api.export_configuration2(panorama, api_key)
        pan_config = PanConfig(xml_config)
        device_groups_and_firewalls = pan_api.get_device_groups_and_firewalls(panorama, api_key)
        active_firewalls = pan_api.get_active_firewalls(panorama, api_key)
        # Build the mapping of active FWs in each device group
        active_firewalls_per_devicegroup = collections.defaultdict(list)
        for dg, firewalls in device_groups_and_firewalls.items():
            active_firewalls_per_devicegroup[dg] = [fw for fw in firewalls if fw in active_firewalls]

    device_group_hierarchy_children, device_group_hierarchy_parent = pan_config.get_device_groups_hierarchy()

    # Build a mapping of device groups to their 'child' device groups
    all_device_groups = pan_config.get_device_groups() + ['shared']
    devicegroups_to_child_devicegroups = squash_all_devicegroups(all_device_groups,
                                                                 device_group_hierarchy_children)

    all_active_firewalls_per_devicegroup = collections.defaultdict(list)
    for dg, child_dgs in devicegroups_to_child_devicegroups.items():
        all_active_firewalls_per_devicegroup[dg] = []
        for child_dg in child_dgs:
            all_active_firewalls_per_devicegroup[dg] += active_firewalls_per_devicegroup[child_dg]

    # Create and fill in the devicegroup_objects, which represents all entries, per devicegroup
    devicegroup_objects = {}

    if device_group:
        device_groups = [device_group]
    else:
        device_groups = all_device_groups

    for device_group in all_device_groups:
        devicegroup_objects[device_group] = {}
        devicegroup_objects[device_group]['all_child_device_groups'] = devicegroups_to_child_devicegroups[device_group]
        devicegroup_objects[device_group]['all_active_child_firewalls'] = all_active_firewalls_per_devicegroup[
            device_group]

        for policy_type in pan_config.SUPPORTED_POLICY_TYPES:
            devicegroup_objects[device_group][policy_type] = pan_config.get_devicegroup_policy(policy_type, device_group)[:limit]
        for object_type in pan_config.SUPPORTED_OBJECT_TYPES:
            devicegroup_objects[device_group][object_type] = pan_config.get_devicegroup_object(object_type, device_group)

    rule_limit_enabled = limit is not None

    # Build a listing of policy objects that are exclusive to each device group, which won't include policies inherited from the parent device groups
    devicegroup_exclusive_objects = {}
    for device_group in all_device_groups:
        devicegroup_exclusive_objects[device_group] = {}

        for policy_type in pan_config.SUPPORTED_POLICY_TYPES:
            if device_group not in device_group_hierarchy_parent:
                # No parent means no inherited policies
                devicegroup_exclusive_objects[device_group][policy_type] = devicegroup_objects[device_group][
                    policy_type]
            else:
                parent_dg = device_group_hierarchy_parent[device_group]
                parent_policy_uuids = set([entry.get('@uuid') for entry in devicegroup_objects[parent_dg][policy_type]])
                exclusive_objects = [entry for entry in devicegroup_objects[device_group][policy_type] if
                                     entry.get('@uuid') not in parent_policy_uuids]
                devicegroup_exclusive_objects[device_group][policy_type] = exclusive_objects

    profilepackage = ProfilePackage(
        api_key=api_key,
        pan_config=pan_config,
        settings=configuration_settings,
        device_group_hierarchy_children=device_group_hierarchy_children,
        device_group_hierarchy_parent=device_group_hierarchy_parent,
        device_groups_and_firewalls=device_groups_and_firewalls,
        device_groups=device_groups,
        devicegroup_objects=devicegroup_objects,
        devicegroup_exclusive_objects=devicegroup_exclusive_objects,
        rule_limit_enabled=rule_limit_enabled,
        no_api=no_api
    )
    return profilepackage