Exemplo n.º 1
0
    def check_references_from_others(self,
                                     rpsl_obj: RPSLObject) -> ValidatorResult:
        """
        Check for any references to this object in the DB.
        Used for validating deletions.

        Checks self._preload_deleted, because a reference from an object
        that is also about to be deleted, is acceptable.
        """
        result = ValidatorResult()
        if not rpsl_obj.references_strong_inbound():
            return result

        query = RPSLDatabaseQuery().sources([rpsl_obj.source()])
        query = query.lookup_attrs_in(rpsl_obj.references_strong_inbound(),
                                      [rpsl_obj.pk()])
        query_results = self.database_handler.execute_query(query)
        for query_result in query_results:
            reference_to_be_deleted = (
                query_result['object_class'], query_result['rpsl_pk'],
                query_result['source']) in self._preloaded_deleted
            if not reference_to_be_deleted:
                result.error_messages.add(
                    f'Object {rpsl_obj.pk()} to be deleted, but still referenced '
                    f'by {query_result["object_class"]} {query_result["rpsl_pk"]}'
                )
        return result
Exemplo n.º 2
0
 def validate(self, rpsl_obj: RPSLObject,
              request_type: UpdateRequestType) -> ValidatorResult:
     result = ValidatorResult()
     if request_type == UpdateRequestType.CREATE and rpsl_obj.rpsl_object_class == 'mntner' and \
             self._check_suspended_mntner_with_same_pk(rpsl_obj.pk(), rpsl_obj.source()):
         result.error_messages.add(
             f'A suspended mntner with primary key {rpsl_obj.pk()} already exists for {rpsl_obj.source()}'
         )
     return result
Exemplo n.º 3
0
 def validate_rpsl_object(
         self, rpsl_object: RPSLObject) -> Tuple[ScopeFilterStatus, str]:
     """
     Validate whether an RPSLObject is in scope.
     Returns a tuple of a ScopeFilterStatus and an explanation string.
     """
     return self._validate_rpsl_data(
         rpsl_object.source(),
         rpsl_object.rpsl_object_class,
         rpsl_object.prefix,
         rpsl_object.asn_first,
     )
Exemplo n.º 4
0
    def check_auth(self, rpsl_obj_new: RPSLObject,
                   rpsl_obj_current: Optional[RPSLObject]) -> ValidatorResult:
        """
        Check whether authentication passes for all required objects.
        """
        source = rpsl_obj_new.source()
        result = ValidatorResult()

        mntners_new = rpsl_obj_new.parsed_data['mnt-by']
        logger.debug(
            f'Checking auth for {rpsl_obj_new}, mntners in new object: {mntners_new}'
        )
        if not self._check_mntners(mntners_new, source):
            self._generate_failure_message(result, mntners_new, rpsl_obj_new)

        if rpsl_obj_current:
            mntners_current = rpsl_obj_current.parsed_data['mnt-by']
            logger.debug(
                f'Checking auth for {rpsl_obj_current}, mntners in new object: {mntners_current}'
            )
            if not self._check_mntners(mntners_current, source):
                self._generate_failure_message(result, mntners_current,
                                               rpsl_obj_new)

        if isinstance(rpsl_obj_new, RPSLMntner):
            # Dummy auth values are only permitted in existing objects, which are never pre-approved.
            if rpsl_obj_new.has_dummy_auth_value() and rpsl_obj_new.pk(
            ) not in self._pre_approved:
                if len(self.passwords) == 1:
                    logger.debug(
                        f'Object {rpsl_obj_new} submitted with dummy hash values and single password, '
                        f'replacing all hashes with currently supplied password.'
                    )
                    rpsl_obj_new.force_single_new_password(self.passwords[0])
                    result.info_messages.add(
                        'As you submitted dummy hash values, all password hashes on this object '
                        'were replaced with a new MD5-PW hash of the password you provided for '
                        'authentication.')
                else:
                    result.error_messages.add(
                        f'Object submitted with dummy hash values, but multiple or no passwords '
                        f'submitted. Either submit all full hashes, or a single password.'
                    )
            elif not rpsl_obj_new.verify_auth(self.passwords,
                                              self.keycert_obj_pk):
                result.error_messages.add(
                    f'Authorisation failed for the auth methods on this mntner object.'
                )

        return result
Exemplo n.º 5
0
    def check_references_to_others(self, rpsl_obj: RPSLObject) -> ValidatorResult:
        """
        Check the validity of references of a particular object, i.e. whether
        all references to other objects actually exist in the database.
        """
        result = ValidatorResult()
        references = rpsl_obj.referred_strong_objects()
        source = rpsl_obj.source()

        for field_name, objects_referred, object_pks in references:
            for object_pk in object_pks:
                if not self._check_reference_to_others(objects_referred, object_pk, source):
                    if len(objects_referred) > 1:
                        objects_referred_str = 'one of ' + ', '.join(objects_referred)
                    else:
                        objects_referred_str = objects_referred[0]
                    result.error_messages.add(f'Object {object_pk} referenced in field {field_name} not found in '
                                              f'database {source} - must reference {objects_referred_str}.')
        return result
Exemplo n.º 6
0
    def process_auth(self, rpsl_obj_new: RPSLObject, rpsl_obj_current: Optional[RPSLObject]) -> ValidatorResult:
        """
        Check whether authentication passes for all required objects.
        Returns a ValidatorResult object with error/info messages, and fills
        result.mntners_notify with the RPSLMntner objects that may have
        to be notified.

        If a valid override password is provided, changes are immediately approved.
        On the result object, used_override is set to True, but mntners_notify is
        not filled, as mntner resolving does not take place.
        """
        source = rpsl_obj_new.source()
        result = ValidatorResult()

        override_hash = get_setting('auth.override_password')
        if override_hash:
            for override in self.overrides:
                try:
                    if md5_crypt.verify(override, override_hash):
                        result.used_override = True
                        logger.debug(f'Found valid override password.')
                        return result
                    else:
                        logger.info(f'Found invalid override password, ignoring.')
                except ValueError as ve:
                    logger.error(f'Exception occurred while checking override password: {ve} (possible misconfigured hash?)')
        elif self.overrides:
            logger.info(f'Ignoring override password, auth.override_password not set.')

        mntners_new = rpsl_obj_new.parsed_data['mnt-by']
        logger.debug(f'Checking auth for new object {rpsl_obj_new}, mntners in new object: {mntners_new}')
        valid, mntner_objs_new = self._check_mntners(mntners_new, source)
        if not valid:
            self._generate_failure_message(result, mntners_new, rpsl_obj_new)

        if rpsl_obj_current:
            mntners_current = rpsl_obj_current.parsed_data['mnt-by']
            logger.debug(f'Checking auth for current object {rpsl_obj_current}, '
                         f'mntners in new object: {mntners_current}')
            valid, mntner_objs_current = self._check_mntners(mntners_current, source)
            if not valid:
                self._generate_failure_message(result, mntners_current, rpsl_obj_new)

            result.mntners_notify = mntner_objs_current
        else:
            result.mntners_notify = mntner_objs_new

        if isinstance(rpsl_obj_new, RPSLMntner):
            if not rpsl_obj_current:
                result.error_messages.add('New mntner objects must be added by an administrator.')
                return result
            # Dummy auth values are only permitted in existing objects
            if rpsl_obj_new.has_dummy_auth_value():
                if len(self.passwords) == 1:
                    logger.debug(f'Object {rpsl_obj_new} submitted with dummy hash values and single password, '
                                 f'replacing all hashes with currently supplied password.')
                    rpsl_obj_new.force_single_new_password(self.passwords[0])
                    result.info_messages.add('As you submitted dummy hash values, all password hashes on this object '
                                             'were replaced with a new MD5-PW hash of the password you provided for '
                                             'authentication.')
                else:
                    result.error_messages.add(f'Object submitted with dummy hash values, but multiple or no passwords '
                                              f'submitted. Either submit only full hashes, or a single password.')
            elif not rpsl_obj_new.verify_auth(self.passwords, self.keycert_obj_pk):
                result.error_messages.add(f'Authorisation failed for the auth methods on this mntner object.')

        return result
Exemplo n.º 7
0
def _init_related_object_query(rpsl_object_class: str,
                               rpsl_obj_new: RPSLObject) -> RPSLDatabaseQuery:
    query = RPSLDatabaseQuery().sources([rpsl_obj_new.source()])
    query = query.object_classes([rpsl_object_class])
    return query.first_only()
Exemplo n.º 8
0
    def process_auth(
            self, rpsl_obj_new: RPSLObject,
            rpsl_obj_current: Optional[RPSLObject]) -> ValidatorResult:
        """
        Check whether authentication passes for all required objects.
        Returns a ValidatorResult object with error/info messages, and fills
        result.mntners_notify with the RPSLMntner objects that may have
        to be notified.

        If a valid override password is provided, changes are immediately approved.
        On the result object, used_override is set to True, but mntners_notify is
        not filled, as mntner resolving does not take place.
        """
        source = rpsl_obj_new.source()
        result = ValidatorResult()

        if self.check_override():
            result.used_override = True
            logger.debug('Found valid override password.')
            return result

        mntners_new = rpsl_obj_new.parsed_data['mnt-by']
        logger.debug(
            f'Checking auth for new object {rpsl_obj_new}, mntners in new object: {mntners_new}'
        )
        valid, mntner_objs_new = self._check_mntners(mntners_new, source)
        if not valid:
            self._generate_failure_message(result, mntners_new, rpsl_obj_new)

        if rpsl_obj_current:
            mntners_current = rpsl_obj_current.parsed_data['mnt-by']
            logger.debug(
                f'Checking auth for current object {rpsl_obj_current}, '
                f'mntners in new object: {mntners_current}')
            valid, mntner_objs_current = self._check_mntners(
                mntners_current, source)
            if not valid:
                self._generate_failure_message(result, mntners_current,
                                               rpsl_obj_new)

            result.mntners_notify = mntner_objs_current
        else:
            result.mntners_notify = mntner_objs_new
            mntners_related = self._find_related_mntners(rpsl_obj_new, result)
            if mntners_related:
                related_object_class, related_pk, related_mntner_list = mntners_related
                logger.debug(
                    f'Checking auth for related object {related_object_class} / '
                    f'{related_pk} with mntners {related_mntner_list}')
                valid, mntner_objs_related = self._check_mntners(
                    related_mntner_list, source)
                if not valid:
                    self._generate_failure_message(result, related_mntner_list,
                                                   rpsl_obj_new,
                                                   related_object_class,
                                                   related_pk)
                    result.mntners_notify = mntner_objs_related

        if isinstance(rpsl_obj_new, RPSLMntner):
            if not rpsl_obj_current:
                result.error_messages.add(
                    'New mntner objects must be added by an administrator.')
                return result
            # Dummy auth values are only permitted in existing objects
            if rpsl_obj_new.has_dummy_auth_value():
                if len(self.passwords) == 1:
                    logger.debug(
                        f'Object {rpsl_obj_new} submitted with dummy hash values and single password, '
                        f'replacing all hashes with currently supplied password.'
                    )
                    rpsl_obj_new.force_single_new_password(self.passwords[0])
                    result.info_messages.add(
                        'As you submitted dummy hash values, all password hashes on this object '
                        'were replaced with a new BCRYPT-PW hash of the password you provided for '
                        'authentication.')
                else:
                    result.error_messages.add(
                        'Object submitted with dummy hash values, but multiple or no passwords '
                        'submitted. Either submit only full hashes, or a single password.'
                    )
            elif not rpsl_obj_new.verify_auth(self.passwords,
                                              self.keycert_obj_pk):
                result.error_messages.add(
                    'Authorisation failed for the auth methods on this mntner object.'
                )

        return result