Пример #1
0
    def test_coauthor_api_key_in_submission_is_found(self):
        coauthor = user_factory()
        AddonUser.objects.create(addon=self.addon, user_id=coauthor.id)
        upload = self.get_upload(abspath=self.file,
                                 with_validation=False,
                                 addon=self.addon,
                                 user=coauthor)
        tasks.validate(upload, listed=True)

        upload.refresh_from_db()

        assert upload.processed_validation['errors'] == 1
        messages = upload.processed_validation['messages']
        assert len(messages) == 1
        assert messages[0]['id'] == [
            'validation', 'messages', 'api_key_detected'
        ]
        assert ('The developer API key of a coauthor was found in the '
                'submitted file.' in messages[0]['message'])
        assert not upload.valid

        # If the key has been revoked, there is no active key,
        # so `get_jwt_key` raises `DoesNotExist`.
        with pytest.raises(APIKey.DoesNotExist):
            APIKey.get_jwt_key(user_id=self.user.id)

        assert len(mail.outbox) == 1
        assert 'Your AMO API credentials have been revoked' in mail.outbox[
            0].subject
        assert 'never share your credentials' in mail.outbox[0].body
        # We submit as the coauthor, the leaked key is the one from 'self.user'
        assert mail.outbox[0].to[0] == self.user.email
    def test_api_key_in_submission_is_found(self):
        upload = FileUpload.objects.create(path=self.file,
                                           addon=self.addon,
                                           user=self.user)
        tasks.validate(upload, listed=True)

        upload.refresh_from_db()

        assert upload.processed_validation['errors'] == 1
        messages = upload.processed_validation['messages']
        assert len(messages) == 1
        assert messages[0]['id'] == [
            u'validation', u'messages', u'api_key_detected'
        ]
        assert ('Your developer API key was found in the submitted '
                'file.' in messages[0]['message'])
        assert not upload.valid

        # If the key has been revoked, there is no active key,
        # so `get_jwt_key` raises `DoesNotExist`.
        with pytest.raises(APIKey.DoesNotExist):
            APIKey.get_jwt_key(user_id=self.user.id)

        assert len(mail.outbox) == 1
        assert ('Your AMO API credentials have been revoked'
                in mail.outbox[0].subject)
        assert ('never share your credentials' in mail.outbox[0].body)
        assert mail.outbox[0].to[0] == self.user.email
 def test_api_key_already_revoked_by_developer(self):
     self.key.update(is_active=None)
     tasks.revoke_api_key(self.key.id)
     # If the key has already been revoked, there is no active key,
     # so `get_jwt_key` raises `DoesNotExist`.
     with pytest.raises(APIKey.DoesNotExist):
         APIKey.get_jwt_key(user_id=self.user.id)
Пример #4
0
 def test_api_key_already_revoked_by_developer(self):
     self.key.update(is_active=None)
     tasks.revoke_api_key(self.key.id)
     # If the key has already been revoked, there is no active key,
     # so `get_jwt_key` raises `DoesNotExist`.
     with pytest.raises(APIKey.DoesNotExist):
         APIKey.get_jwt_key(user_id=self.user.id)
Пример #5
0
    def test_coauthor_api_key_in_submission_is_found(self):
        coauthor = user_factory()
        AddonUser.objects.create(addon=self.addon, user_id=coauthor.id)
        upload = FileUpload.objects.create(path=self.file, addon=self.addon,
                                           user=coauthor)
        tasks.validate(upload, listed=True)

        upload.refresh_from_db()

        assert upload.processed_validation['errors'] == 1
        messages = upload.processed_validation['messages']
        assert len(messages) == 1
        assert messages[0]['id'] == [
            u'validation', u'messages', u'api_key_detected']
        assert ('The developer API key of a coauthor was found in the '
                'submitted file.' in messages[0]['message'])
        assert not upload.valid

        # If the key has been revoked, there is no active key,
        # so `get_jwt_key` raises `DoesNotExist`.
        with pytest.raises(APIKey.DoesNotExist):
            APIKey.get_jwt_key(user_id=self.user.id)

        assert len(mail.outbox) == 1
        assert ('Your AMO API credentials have been revoked'
                in mail.outbox[0].subject)
        assert ('never share your credentials' in mail.outbox[0].body)
        # We submit as the coauthor, the leaked key is the one from 'self.user'
        assert mail.outbox[0].to[0] == self.user.email
Пример #6
0
def revoke_api_key(key_id):
    try:
        # Fetch the original key, do not use `get_jwt_key`
        # so we get access to a user object for logging later.
        original_key = APIKey.objects.get(type=SYMMETRIC_JWT_TYPE, id=key_id)
        # Fetch the current key to compare to the original,
        # throws if the key has been revoked, which also means
        # `original_key` is not active.
        current_key = APIKey.get_jwt_key(user_id=original_key.user.id)
        if current_key.key != original_key.key:
            log.info(
                'User %s has already regenerated the key, nothing to be '
                'done.' % original_key.user
            )
        else:
            with transaction.atomic():
                log.info('Revoking key for user %s.' % current_key.user)
                current_key.update(is_active=None)
                send_api_key_revocation_email(emails=[current_key.user.email])
    except APIKey.DoesNotExist:
        log.info(
            'User %s has already revoked the key, nothing to be done.'
            % original_key.user
        )
        pass
 def test_api_key_already_regenerated_by_developer(self):
     self.key.update(is_active=None)
     current_key = APIKey.new_jwt_credentials(user=self.user)
     tasks.revoke_api_key(self.key.id)
     key_from_db = APIKey.get_jwt_key(user_id=self.user.id)
     assert current_key.key == key_from_db.key
     assert current_key.secret == key_from_db.secret
Пример #8
0
 def test_api_key_already_regenerated_by_developer(self):
     self.key.update(is_active=None)
     current_key = APIKey.new_jwt_credentials(user=self.user)
     tasks.revoke_api_key(self.key.id)
     key_from_db = APIKey.get_jwt_key(user_id=self.user.id)
     assert current_key.key == key_from_db.key
     assert current_key.secret == key_from_db.secret
Пример #9
0
def check_for_api_keys_in_file(results, upload_pk):
    upload = FileUpload.objects.get(pk=upload_pk)

    if upload.addon:
        users = upload.addon.authors.all()
    else:
        users = [upload.user] if upload.user else []

    keys = []
    for user in users:
        try:
            key = APIKey.get_jwt_key(user_id=user.id)
            keys.append(key)
        except APIKey.DoesNotExist:
            pass

    try:
        if len(keys) > 0:
            zipfile = SafeZip(source=upload.path)
            for zipinfo in zipfile.info_list:
                if zipinfo.file_size >= 64:
                    file_ = zipfile.read(zipinfo)
                    for key in keys:
                        if key.secret in file_.decode(errors='ignore'):
                            log.info('Developer API key for user %s found in '
                                     'submission.' % key.user)
                            if key.user == upload.user:
                                msg = gettext('Your developer API key was '
                                              'found in the submitted file. '
                                              'To protect your account, the '
                                              'key will be revoked.')
                            else:
                                msg = gettext('The developer API key of a '
                                              'coauthor was found in the '
                                              'submitted file. To protect '
                                              'your add-on, the key will be '
                                              'revoked.')
                            annotations.insert_validation_message(
                                results,
                                type_='error',
                                message=msg,
                                msg_id='api_key_detected',
                                compatibility_type=None,
                            )

                            # Revoke after 2 minutes to allow the developer to
                            # fetch the validation results
                            revoke_api_key.apply_async(
                                kwargs={'key_id': key.id}, countdown=120)
            zipfile.close()
    except (ValidationError, BadZipFile, IOError):
        pass

    return results
Пример #10
0
    def test_api_key_in_new_submission_is_found(self):
        upload = FileUpload.objects.create(path=self.file, user=self.user)
        tasks.validate(upload, listed=True)

        upload.refresh_from_db()

        assert upload.processed_validation['errors'] == 1
        messages = upload.processed_validation['messages']
        assert len(messages) == 1
        assert messages[0]['id'] == [
            u'validation', u'messages', u'api_key_detected']
        assert ('Your developer API key was found in the submitted '
                'file.' in messages[0]['message'])
        assert not upload.valid

        # If the key has been revoked, there is no active key,
        # so `get_jwt_key` raises `DoesNotExist`.
        with pytest.raises(APIKey.DoesNotExist):
            APIKey.get_jwt_key(user_id=self.user.id)

        assert len(mail.outbox) == 1
        assert ('Your AMO API credentials have been revoked'
                in mail.outbox[0].subject)
        assert mail.outbox[0].to[0] == self.user.email
Пример #11
0
def check_for_api_keys_in_file(results, upload):
    if upload.addon:
        users = upload.addon.authors.all()
    else:
        users = [upload.user] if upload.user else []

    keys = []
    for user in users:
        try:
            key = APIKey.get_jwt_key(user_id=user.id)
            keys.append(key)
        except APIKey.DoesNotExist:
            pass

    if len(keys) > 0:
        zipfile = SafeZip(source=upload.path)
        zipfile.is_valid()
        for zipinfo in zipfile.info_list:
            if zipinfo.file_size >= 64:
                file_ = zipfile.read(zipinfo)
                for key in keys:
                    if key.secret in file_.decode(encoding='unicode-escape',
                                                  errors="ignore"):
                        log.info('Developer API key for user %s found in '
                                 'submission.' % key.user)
                        if key.user == upload.user:
                            msg = ugettext('Your developer API key was found '
                                           'in the submitted file. To protect '
                                           'your account, the key will be '
                                           'revoked.')
                        else:
                            msg = ugettext('The developer API key of a '
                                           'coauthor was found in the '
                                           'submitted file. To protect your '
                                           'add-on, the key will be revoked.')
                        insert_validation_message(
                            results, type_='error',
                            message=msg, msg_id='api_key_detected',
                            compatibility_type=None)

                        # Revoke after 2 minutes to allow the developer to
                        # fetch the validation results
                        revoke_api_key.apply_async(
                            kwargs={'key_id': key.id}, countdown=120)
        zipfile.close()

    return results
Пример #12
0
    def authenticate_credentials(self, payload):
        """
        Returns a verified AMO user who is active and allowed to make API
        requests.
        """
        try:
            api_key = APIKey.get_jwt_key(key=payload['iss'])
        except APIKey.DoesNotExist:
            msg = 'Invalid API Key.'
            raise exceptions.AuthenticationFailed(msg)

        if api_key.user.deleted:
            msg = 'User account is disabled.'
            raise exceptions.AuthenticationFailed(msg)
        if not api_key.user.read_dev_agreement:
            msg = 'User has not read developer agreement.'
            raise exceptions.AuthenticationFailed(msg)

        return api_key.user
Пример #13
0
    def authenticate_credentials(self, payload):
        """
        Returns a verified AMO user who is active and allowed to make API
        requests.
        """
        try:
            api_key = APIKey.get_jwt_key(key=payload['iss'])
        except APIKey.DoesNotExist:
            msg = 'Invalid API Key.'
            raise exceptions.AuthenticationFailed(msg)

        if api_key.user.deleted:
            msg = 'User account is disabled.'
            raise exceptions.AuthenticationFailed(msg)
        if not api_key.user.read_dev_agreement:
            msg = 'User has not read developer agreement.'
            raise exceptions.AuthenticationFailed(msg)

        return api_key.user
Пример #14
0
def revoke_api_key(key_id):
    try:
        # Fetch the original key, do not use `get_jwt_key`
        # so we get access to a user object for logging later.
        original_key = APIKey.objects.get(
            type=SYMMETRIC_JWT_TYPE, id=key_id)
        # Fetch the current key to compare to the original,
        # throws if the key has been revoked, which also means
        # `original_key` is not active.
        current_key = APIKey.get_jwt_key(user_id=original_key.user.id)
        if current_key.key != original_key.key:
            log.info('User %s has already regenerated the key, nothing to be '
                     'done.' % original_key.user)
        else:
            with transaction.atomic():
                log.info('Revoking key for user %s.' % current_key.user)
                current_key.update(is_active=None)
                send_api_key_revocation_email(emails=[current_key.user.email])
    except APIKey.DoesNotExist:
        log.info('User %s has already revoked the key, nothing to be done.'
                 % original_key.user)
        pass
Пример #15
0
    def authenticate_credentials(self, payload):
        """
        Returns a verified AMO user who is active and allowed to make API
        requests.
        """
        if 'orig_iat' in payload:
            msg = ("API key based tokens are not refreshable, don't include "
                   '`orig_iat` in their payload.')
            raise exceptions.AuthenticationFailed(msg)
        try:
            api_key = APIKey.get_jwt_key(key=payload['iss'])
        except APIKey.DoesNotExist:
            msg = 'Invalid API Key.'
            raise exceptions.AuthenticationFailed(msg)

        if api_key.user.deleted:
            msg = 'User account is disabled.'
            raise exceptions.AuthenticationFailed(msg)
        if not api_key.user.read_dev_agreement:
            msg = 'User has not read developer agreement.'
            raise exceptions.AuthenticationFailed(msg)

        core.set_user(api_key.user)
        return api_key.user
Пример #16
0
    def authenticate_credentials(self, payload):
        """
        Returns a verified AMO user who is active and allowed to make API
        requests.
        """
        if 'orig_iat' in payload:
            msg = ("API key based tokens are not refreshable, don't include "
                   "`orig_iat` in their payload.")
            raise exceptions.AuthenticationFailed(msg)
        try:
            api_key = APIKey.get_jwt_key(key=payload['iss'])
        except APIKey.DoesNotExist:
            msg = 'Invalid API Key.'
            raise exceptions.AuthenticationFailed(msg)

        if api_key.user.deleted:
            msg = 'User account is disabled.'
            raise exceptions.AuthenticationFailed(msg)
        if not api_key.user.read_dev_agreement:
            msg = 'User has not read developer agreement.'
            raise exceptions.AuthenticationFailed(msg)

        amo.set_user(api_key.user)
        return api_key.user