Exemplo n.º 1
0
    def validate_testing_farm_request():
        """
        Validate testing farm token received in request with the one in packit-service.yaml

        Currently we use the same secret to authenticate both,
        packit service (when sending request to testing farm)
        and testing farm (when sending notification to packit service's webhook).
        We might later use a different secret for those use cases.

        :raises ValidationFailed
        """
        if not config.testing_farm_secret:
            msg = "Testing farm secret not specified in config"
            logger.error(msg)
            raise ValidationFailed(msg)

        token = request.json.get("token")
        if not token:
            msg = "The notification doesn't contain any token"
            logger.info(msg)
            raise ValidationFailed(msg)

        if token == config.testing_farm_secret or (
                config.internal_testing_farm_secret
                and token == config.internal_testing_farm_secret):
            return

        msg = "Invalid testing farm secret provided"
        logger.warning(msg)
        raise ValidationFailed(msg)
Exemplo n.º 2
0
    def validate_token(self):
        """
        https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#secret-token
        """
        if "X-Gitlab-Token" not in request.headers:
            if config.validate_webhooks:
                msg = "X-Gitlab-Token not in request.headers"
                logger.info(msg)
                self.create_confidential_issue_with_token()
                return
            else:
                # don't validate signatures when testing locally
                logger.debug("Ain't validating token.")
                return

        token = request.headers["X-Gitlab-Token"]

        if token in config.gitlab_webhook_tokens:
            logger.debug("Deprecation Warning: Old Gitlab tokens used.")
            return

        gitlab_token_secret = config.gitlab_token_secret
        if not gitlab_token_secret:
            msg = "'gitlab_token_secret' not specified in the config."
            logger.error(msg)
            raise ValidationFailed(msg)

        try:
            token_decoded = jwt.decode(token,
                                       config.gitlab_token_secret,
                                       algorithms=["HS256"])
        except jwt.exceptions.InvalidSignatureError:
            msg_failed_signature = "Payload token does not match the project."
            logger.warning(msg_failed_signature)
            raise ValidationFailed(msg_failed_signature)
        except jwt.exceptions.DecodeError:
            msg_failed_error = "Payload token has invalid signature."
            logger.warning(msg_failed_error)
            raise ValidationFailed(msg_failed_error)

        project_data = json.loads(request.data)["project"]
        parsed_url = parse_git_repo(potential_url=project_data["http_url"])
        token_namespace = token_decoded["namespace"]
        token_repo_name = token_decoded["repo_name"]

        if (token_namespace, token_repo_name) == (
                parsed_url.namespace,
                parsed_url.repo,
        ):
            logger.debug("Payload signature is OK.")
        else:
            msg_failed_validation = "Signature of the payload token is not valid."
            logger.warning(msg_failed_validation)
            raise ValidationFailed(msg_failed_validation)
Exemplo n.º 3
0
    def validate_token(self):
        """
        https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#secret-token
        """
        if "X-Gitlab-Token" not in request.headers:
            if config.validate_webhooks:
                msg = "X-Gitlab-Token not in request.headers"
                logger.info(msg)
                self.create_confidential_issue_with_token()
                raise ValidationFailed(msg)
            else:
                # don't validate signatures when testing locally
                logger.debug("Ain't validating token.")
                return

        token = request.headers["X-Gitlab-Token"]

        gitlab_token_secret = config.gitlab_token_secret
        if not gitlab_token_secret:
            msg = "'gitlab_token_secret' not specified in the config."
            logger.error(msg)
            raise ValidationFailed(msg)

        try:
            token_decoded = jwt.decode(token,
                                       config.gitlab_token_secret,
                                       algorithms=["HS256"])
        except (
                jwt.exceptions.InvalidSignatureError,
                jwt.exceptions.DecodeError,
        ) as exc:
            msg_failed_error = "Can't decode X-Gitlab-Token."
            logger.warning(f"{msg_failed_error} {exc}")
            raise ValidationFailed(msg_failed_error) from exc

        project_data = json.loads(request.data)["project"]
        git_http_url = project_data.get(
            "git_http_url") or project_data["http_url"]
        parsed_url = parse_git_repo(potential_url=git_http_url)

        # "repo_name" might be missing in token_decoded if the token is for group/namespace
        if token_decoded["namespace"] != parsed_url.namespace or (
                "repo_name" in token_decoded
                and token_decoded["repo_name"] != parsed_url.repo):
            msg_failed_validation = (
                "Decoded X-Gitlab-Token does not match namespace[/project].")
            logger.warning(msg_failed_validation)
            logger.debug(f"decoded: {token_decoded}, url: {parsed_url}")
            raise ValidationFailed(msg_failed_validation)

        logger.debug("Payload signature is OK.")
Exemplo n.º 4
0
    def validate_testing_farm_request():
        """
        Validate testing farm token received in request with the one in packit-service.yaml
        :raises ValidationFailed
        """
        if not config.testing_farm_secret:
            msg = "Testing farm secret not specified in config"
            logger.error(msg)
            raise ValidationFailed(msg)

        token = request.json.get("token")
        if not token:
            msg = "The request doesn't contain any token"
            logger.info(msg)
            raise ValidationFailed(msg)
        if token == config.testing_farm_secret:
            return

        msg = "Invalid testing farm secret provided"
        logger.warning(msg)
        raise ValidationFailed(msg)
Exemplo n.º 5
0
    def validate_token():
        """
        https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#secret-token
        """
        if "X-Gitlab-Token" not in request.headers:
            if config.validate_webhooks:
                msg = "X-Gitlab-Token not in request.headers"
                logger.warning(msg)
                raise ValidationFailed(msg)
            else:
                # don't validate signatures when testing locally
                logger.debug("Ain't validating token.")
                return

        token = request.headers["X-Gitlab-Token"]

        # Find a better solution
        if token != config.gitlab_webhook_token:
            raise ValidationFailed("Payload token validation failed.")

        logger.debug("Payload token is OK.")
Exemplo n.º 6
0
    def validate_signature():
        """
        https://developer.github.com/webhooks/securing/#validating-payloads-from-github
        https://developer.github.com/webhooks/#delivery-headers
        """
        if "X-Hub-Signature" not in request.headers:
            if config.validate_webhooks:
                msg = "X-Hub-Signature not in request.headers"
                logger.warning(msg)
                raise ValidationFailed(msg)
            else:
                # don't validate signatures when testing locally
                logger.debug("Ain't validating signatures.")
                return

        sig = request.headers["X-Hub-Signature"]
        if not sig.startswith("sha1="):
            msg = f"Digest mode in X-Hub-Signature {sig!r} is not sha1."
            logger.warning(msg)
            raise ValidationFailed(msg)

        webhook_secret = config.webhook_secret.encode()
        if not webhook_secret:
            msg = "'webhook_secret' not specified in the config."
            logger.error(msg)
            raise ValidationFailed(msg)

        signature = sig.split("=")[1]
        mac = hmac.new(webhook_secret, msg=request.get_data(), digestmod=sha1)
        digest_is_valid = hmac.compare_digest(signature, mac.hexdigest())
        if digest_is_valid:
            logger.debug("Payload signature OK.")
        else:
            msg = "Payload signature validation failed."
            logger.warning(msg)
            logger.debug(
                f"X-Hub-Signature: {sig!r} != computed: {mac.hexdigest()}")
            raise ValidationFailed(msg)