예제 #1
0
 def test_check_alpn_protocols(self):
     # Test valid list
     validate.check_alpn_protocols(['h2', 'http/1.1', 'http/1.0'])
     # Test invalid list
     self.assertRaises(exceptions.ValidationException,
                       validate.check_alpn_protocols,
                       ['httpie', 'foobar/1.2.3'])
     # Test empty list
     self.assertRaises(exceptions.ValidationException,
                       validate.check_alpn_protocols, [])
예제 #2
0
파일: pool.py 프로젝트: ycx516/octavia
    def _validate_create_pool(self, lock_session, pool_dict, listener_id=None):
        """Validate creating pool on load balancer.

        Update database for load balancer and (optional) listener based on
        provisioning status.
        """
        # Make sure we have a client CA if they specify a CRL
        if (pool_dict.get('crl_container_id')
                and not pool_dict.get('ca_tls_certificate_id')):
            raise exceptions.ValidationException(
                detail=_("A CA certificate reference is required to "
                         "specify a revocation list."))

        tls_certificate_id = pool_dict.get('tls_certificate_id', None)
        tls_refs = [tls_certificate_id] if tls_certificate_id else []
        self._validate_tls_refs(tls_refs)

        # Validate the client CA cert and optional client CRL
        if pool_dict.get('ca_tls_certificate_id'):
            self._validate_client_ca_and_crl_refs(
                pool_dict.get('ca_tls_certificate_id'),
                pool_dict.get('crl_container_id', None))

        # Check TLS cipher prohibit list
        if 'tls_ciphers' in pool_dict and pool_dict['tls_ciphers']:
            rejected_ciphers = validate.check_cipher_prohibit_list(
                pool_dict['tls_ciphers'])
            if rejected_ciphers:
                raise exceptions.ValidationException(detail=_(
                    'The following ciphers have been prohibited by an '
                    'administrator: ' + ', '.join(rejected_ciphers)))

        if pool_dict['tls_enabled']:
            # Validate TLS version list
            validate.check_tls_version_list(pool_dict['tls_versions'])
            # Validate TLS versions against minimum
            validate.check_tls_version_min(pool_dict['tls_versions'])
            # Validate ALPN protocol list
            validate.check_alpn_protocols(pool_dict['alpn_protocols'])

        try:
            return self.repositories.create_pool_on_load_balancer(
                lock_session, pool_dict, listener_id=listener_id)
        except odb_exceptions.DBDuplicateEntry as e:
            raise exceptions.IDAlreadyExists() from e
        except odb_exceptions.DBError as e:
            # TODO(blogan): will have to do separate validation protocol
            # before creation or update since the exception messages
            # do not give any information as to what constraint failed
            raise exceptions.InvalidOption(value='', option='') from e
예제 #3
0
    def _validate_listener_PUT(self, listener, db_listener):
        # TODO(rm_work): Do we need something like this? What do we do on an
        # empty body for a PUT?
        if not listener:
            raise exceptions.ValidationException(
                detail='No listener object supplied.')

        # Check for UDP/SCTP compatibility
        if (db_listener.protocol in (constants.PROTOCOL_UDP,
                                     lib_consts.PROTOCOL_SCTP) and
                self._is_tls_or_insert_header(listener.to_dict())):
            raise exceptions.ValidationException(detail=_(
                "%s protocol listener does not support TLS or header "
                "insertion.") % db_listener.protocol)

        # Check for certs when not TERMINATED_HTTPS
        if (db_listener.protocol != constants.PROTOCOL_TERMINATED_HTTPS and
                self._has_tls_container_refs(listener.to_dict())):
            raise exceptions.ValidationException(detail=_(
                "Certificate container references are only allowed on "
                "%s protocol listeners.") %
                constants.PROTOCOL_TERMINATED_HTTPS)

        # Make sure we have a client CA cert if they enable client auth
        if ((listener.client_authentication != wtypes.Unset and
             listener.client_authentication != constants.CLIENT_AUTH_NONE) and
            not (db_listener.client_ca_tls_certificate_id or
                 listener.client_ca_tls_container_ref)):
            raise exceptions.ValidationException(detail=_(
                "Client authentication setting %s requires a client CA "
                "container reference.") %
                listener.client_authentication)

        if listener.insert_headers:
            self._validate_insert_headers(
                list(listener.insert_headers.keys()), db_listener.protocol)

        sni_containers = listener.sni_container_refs or []
        tls_refs = list(sni_containers)
        if listener.default_tls_container_ref:
            tls_refs.append(listener.default_tls_container_ref)
        self._validate_tls_refs(tls_refs)

        ca_ref = None
        if (listener.client_ca_tls_container_ref and
                listener.client_ca_tls_container_ref != wtypes.Unset):
            ca_ref = listener.client_ca_tls_container_ref
        elif db_listener.client_ca_tls_certificate_id:
            ca_ref = db_listener.client_ca_tls_certificate_id

        crl_ref = None
        if (listener.client_crl_container_ref and
                listener.client_crl_container_ref != wtypes.Unset):
            crl_ref = listener.client_crl_container_ref
        elif db_listener.client_crl_container_id:
            crl_ref = db_listener.client_crl_container_id

        if crl_ref and not ca_ref:
            raise exceptions.ValidationException(detail=_(
                "A client authentication CA reference is required to "
                "specify a client authentication revocation list."))

        if ca_ref or crl_ref:
            self._validate_client_ca_and_crl_refs(ca_ref, crl_ref)

        # Validate allowed CIDRs
        if (listener.allowed_cidrs and listener.allowed_cidrs != wtypes.Unset):
            vip_address = db_listener.load_balancer.vip.ip_address
            self._validate_cidr_compatible_with_vip(
                vip_address, listener.allowed_cidrs)

        # Check TLS cipher prohibit list
        if listener.tls_ciphers:
            rejected_ciphers = validate.check_cipher_prohibit_list(
                listener.tls_ciphers)
            if rejected_ciphers:
                raise exceptions.ValidationException(detail=_(
                    'The following ciphers have been prohibited by an '
                    'administrator: ' + ', '.join(rejected_ciphers)))

        if listener.tls_versions is not wtypes.Unset:
            # Validate TLS version list
            validate.check_tls_version_list(listener.tls_versions)
            # Validate TLS versions against minimum
            validate.check_tls_version_min(listener.tls_versions)

        if listener.alpn_protocols is not wtypes.Unset:
            # Validate ALPN protocol list
            validate.check_alpn_protocols(listener.alpn_protocols)
예제 #4
0
    def _validate_create_listener(self, lock_session, listener_dict):
        """Validate listener for wrong protocol or duplicate listeners

        Update the load balancer db when provisioning status changes.
        """
        listener_protocol = listener_dict.get('protocol')

        if listener_dict and listener_dict.get('insert_headers'):
            self._validate_insert_headers(
                listener_dict['insert_headers'].keys(), listener_protocol)

        # Check for UDP/SCTP compatibility
        if (listener_protocol in (constants.PROTOCOL_UDP,
                                  lib_consts.PROTOCOL_SCTP) and
                self._is_tls_or_insert_header(listener_dict)):
            raise exceptions.ValidationException(
                detail=_("%s protocol listener does not "
                         "support TLS.") % listener_protocol)

        # Check for TLS disabled
        if (not CONF.api_settings.allow_tls_terminated_listeners and
                listener_protocol == constants.PROTOCOL_TERMINATED_HTTPS):
            raise exceptions.DisabledOption(
                value=constants.PROTOCOL_TERMINATED_HTTPS, option='protocol')

        # Check for certs when not TERMINATED_HTTPS
        if (listener_protocol != constants.PROTOCOL_TERMINATED_HTTPS and
                self._has_tls_container_refs(listener_dict)):
            raise exceptions.ValidationException(detail=_(
                "Certificate container references are only allowed on "
                "%s protocol listeners.") %
                constants.PROTOCOL_TERMINATED_HTTPS)

        # Make sure a base certificate exists if specifying a client ca
        if (listener_dict.get('client_ca_tls_certificate_id') and
            not (listener_dict.get('tls_certificate_id') or
                 listener_dict.get('sni_containers'))):
            raise exceptions.ValidationException(detail=_(
                "An SNI or default certificate container reference must "
                "be provided with a client CA container reference."))

        # Make sure a certificate container is specified for TERMINATED_HTTPS
        if (listener_protocol == constants.PROTOCOL_TERMINATED_HTTPS and
            not (listener_dict.get('tls_certificate_id') or
                 listener_dict.get('sni_containers'))):
            raise exceptions.ValidationException(detail=_(
                "An SNI or default certificate container reference must "
                "be provided for %s protocol listeners.") %
                constants.PROTOCOL_TERMINATED_HTTPS)

        # Make sure we have a client CA cert if they enable client auth
        if (listener_dict.get('client_authentication') !=
            constants.CLIENT_AUTH_NONE and not
                listener_dict.get('client_ca_tls_certificate_id')):
            raise exceptions.ValidationException(detail=_(
                "Client authentication setting %s requires a client CA "
                "container reference.") %
                listener_dict.get('client_authentication'))

        # Make sure we have a client CA if they specify a CRL
        if (listener_dict.get('client_crl_container_id') and
                not listener_dict.get('client_ca_tls_certificate_id')):
            raise exceptions.ValidationException(detail=_(
                "A client authentication CA reference is required to "
                "specify a client authentication revocation list."))

        # Check TLS cipher prohibit list
        if 'tls_ciphers' in listener_dict and listener_dict['tls_ciphers']:
            rejected_ciphers = validate.check_cipher_prohibit_list(
                listener_dict['tls_ciphers'])
            if rejected_ciphers:
                raise exceptions.ValidationException(detail=_(
                    'The following ciphers have been prohibited by an '
                    'administrator: ' + ', '.join(rejected_ciphers)))

        # Validate the TLS containers
        sni_containers = listener_dict.pop('sni_containers', [])
        tls_refs = [sni['tls_container_id'] for sni in sni_containers]
        if listener_dict.get('tls_certificate_id'):
            tls_refs.append(listener_dict.get('tls_certificate_id'))
        self._validate_tls_refs(tls_refs)

        # Validate the client CA cert and optional client CRL
        if listener_dict.get('client_ca_tls_certificate_id'):
            self._validate_client_ca_and_crl_refs(
                listener_dict.get('client_ca_tls_certificate_id'),
                listener_dict.get('client_crl_container_id', None))

        # Validate that the L4 protocol (UDP, TCP or SCTP) is not already used
        # for the specified protocol_port in this load balancer
        pcontext = pecan_request.context
        query_filter = {
            'project_id': listener_dict['project_id'],
            'load_balancer_id': listener_dict['load_balancer_id'],
            'protocol_port': listener_dict['protocol_port']
        }

        # Get listeners on the same load balancer that use the same
        # protocol port
        db_listeners = self.repositories.listener.get_all_API_list(
            lock_session, show_deleted=False,
            pagination_helper=pcontext.get(constants.PAGINATION_HELPER),
            **query_filter)[0]

        if db_listeners:
            l4_protocol = constants.L4_PROTOCOL_MAP[listener_protocol]

            # List supported protocols that share the same L4 protocol as our
            # new listener
            disallowed_protocols = [
                p
                for p in constants.L4_PROTOCOL_MAP
                if constants.L4_PROTOCOL_MAP[p] == l4_protocol
            ]

            for db_l in db_listeners:
                # Check if l4 protocol ports conflict
                if db_l.protocol in disallowed_protocols:
                    raise exceptions.DuplicateListenerEntry(
                        protocol=db_l.protocol,
                        port=listener_dict.get('protocol_port'))

        # Validate allowed CIDRs
        allowed_cidrs = listener_dict.get('allowed_cidrs', []) or []
        lb_id = listener_dict.get('load_balancer_id')
        vip_db = self.repositories.vip.get(
            lock_session, load_balancer_id=lb_id)
        vip_address = vip_db.ip_address
        self._validate_cidr_compatible_with_vip(vip_address, allowed_cidrs)

        if listener_protocol == constants.PROTOCOL_TERMINATED_HTTPS:
            # Validate TLS version list
            validate.check_tls_version_list(listener_dict['tls_versions'])
            # Validate TLS versions against minimum
            validate.check_tls_version_min(listener_dict['tls_versions'])
            # Validate ALPN protocol list
            validate.check_alpn_protocols(listener_dict['alpn_protocols'])

        try:
            db_listener = self.repositories.listener.create(
                lock_session, **listener_dict)
            if sni_containers:
                for container in sni_containers:
                    sni_dict = {'listener_id': db_listener.id,
                                'tls_container_id': container.get(
                                    'tls_container_id')}
                    self.repositories.sni.create(lock_session, **sni_dict)
                # DB listener needs to be refreshed
                db_listener = self.repositories.listener.get(
                    lock_session, id=db_listener.id)

            return db_listener
        except odb_exceptions.DBDuplicateEntry as de:
            column_list = ['load_balancer_id', 'protocol', 'protocol_port']
            constraint_list = ['uq_listener_load_balancer_id_protocol_port']
            if ['id'] == de.columns:
                raise exceptions.IDAlreadyExists()
            if (set(column_list) == set(de.columns) or
                    set(constraint_list) == set(de.columns)):
                raise exceptions.DuplicateListenerEntry(
                    protocol=listener_dict.get('protocol'),
                    port=listener_dict.get('protocol_port'))
        except odb_exceptions.DBError as e:
            raise exceptions.InvalidOption(value=listener_dict.get('protocol'),
                                           option='protocol') from e
예제 #5
0
파일: pool.py 프로젝트: ycx516/octavia
    def _validate_pool_PUT(self, pool, db_pool):

        if db_pool.protocol in (constants.PROTOCOL_UDP,
                                lib_consts.PROTOCOL_SCTP):
            self._validate_pool_request_for_udp_sctp(pool)
        else:
            if (pool.session_persistence
                    and (pool.session_persistence.persistence_timeout
                         or pool.session_persistence.persistence_granularity)):
                raise exceptions.ValidationException(
                    detail=_("persistence_timeout and persistence_granularity "
                             "is only for UDP protocol pools."))

        if pool.session_persistence:
            sp_dict = pool.session_persistence.to_dict(render_unsets=False)
            validate.check_session_persistence(sp_dict)

        crl_ref = None
        # If we got a crl_ref and it's not unset, use it
        if (pool.crl_container_ref and pool.crl_container_ref != wtypes.Unset):
            crl_ref = pool.crl_container_ref
        # If we got Unset and a CRL exists in the DB, use the DB crl_ref
        elif (db_pool.crl_container_id
              and pool.crl_container_ref == wtypes.Unset):
            crl_ref = db_pool.crl_container_id

        ca_ref = None
        db_ca_ref = db_pool.ca_tls_certificate_id
        if pool.ca_tls_container_ref != wtypes.Unset:
            if not pool.ca_tls_container_ref and db_ca_ref and crl_ref:
                raise exceptions.ValidationException(
                    detail=_("A CA reference cannot be removed when a "
                             "certificate revocation list is present."))

            if not pool.ca_tls_container_ref and not db_ca_ref and crl_ref:
                raise exceptions.ValidationException(
                    detail=_("A CA reference is required to "
                             "specify a certificate revocation list."))
            if pool.ca_tls_container_ref:
                ca_ref = pool.ca_tls_container_ref
        elif db_ca_ref and pool.ca_tls_container_ref == wtypes.Unset:
            ca_ref = db_ca_ref
        elif crl_ref and not db_ca_ref:
            raise exceptions.ValidationException(
                detail=_("A CA reference is required to "
                         "specify a certificate revocation list."))

        if pool.tls_container_ref:
            self._validate_tls_refs([pool.tls_container_ref])

        # Validate the client CA cert and optional client CRL
        if ca_ref:
            self._validate_client_ca_and_crl_refs(ca_ref, crl_ref)

        # Check TLS cipher prohibit list
        if pool.tls_ciphers:
            rejected_ciphers = validate.check_cipher_prohibit_list(
                pool.tls_ciphers)
            if rejected_ciphers:
                raise exceptions.ValidationException(detail=_(
                    "The following ciphers have been prohibited by an "
                    "administrator: " + ', '.join(rejected_ciphers)))

        if pool.tls_versions is not wtypes.Unset:
            # Validate TLS version list
            validate.check_tls_version_list(pool.tls_versions)
            # Validate TLS version against minimum
            validate.check_tls_version_min(pool.tls_versions)

        if pool.alpn_protocols is not wtypes.Unset:
            # Validate ALPN protocol list
            validate.check_alpn_protocols(pool.alpn_protocols)