Poetry: Regression: 403 Auth Failure for S3-hosted (Cloudfront) Private Repos

Created on 28 Oct 2020  ยท  6Comments  ยท  Source: python-poetry/poetry

  • [x] I am on the latest Poetry version.
  • [x] I have searched the issues of this repo and believe that this is not a duplicate. (There are similar tickets, notably #3291 but they aren't specifically targeting a repo hosted on S3/Cloudfront)
  • [X] If an exception occurs when executing a command, I executed it again in debug mode (-vvv option).

  • OS version and name: python:3.7-alpine (Docker)

  • Poetry version: 1.1.4
  • Link of a Gist with the contents of your pyproject.toml file: https://gist.github.com/dvf/a117ebdb0358cb388c5145cfdd39b46e

Issue

  • We noticed a regression from Poetry 1.0.3 to 1.1.4.
  • We're using a private PyPI repository hosted on S3 protected by Cloudfront using Basic Auth (we use s3pypi)

When we tried to install a new private dependency, or remove a non-private dependency (with common sub dependencies with a private dependency) we saw this error:

โžœ  project git:(master) poetry remove django-structlog
Updating dependencies
Resolving dependencies... (0.2s)

  RepositoryError

  403 Client Error: Forbidden for url: https://XXXXXXXXXXXXXXXX/pyjwt/

  at ~/.poetry/lib/poetry/repositories/legacy_repository.py:393 in _get
      389โ”‚             if response.status_code == 404:
      390โ”‚                 return
      391โ”‚             response.raise_for_status()
      392โ”‚         except requests.HTTPError as e:
    โ†’ 393โ”‚             raise RepositoryError(e)
      394โ”‚ 
      395โ”‚         if response.status_code in (401, 403):
      396โ”‚             self._log(
      397โ”‚                 "Authorization error accessing {url}".format(url=url), level="warn"

Hypothesis of why this is happening

By default, Cloudfront returns a 403 for non-existing files. This is a good security practice as it prevents leakage of information to unauthenticated parties. However, (from the above code) Poetry only falls back to public PyPI if it encounters a 404 when requesting a package.

Quick fix

The quick fix for this is to have your private repo (in our case Cloudfront) return a default error response code of 404.
Here are docs on how to do that: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/custom-error-pages-response-code.html

Recommendations

Poetry shouldn't fall back to the public repo on a 401/403/404 _without_ first checking if it can successfully auth to the repo. And failing that, it should throw an appropriate error.

Thanks to @proxyroot and @vagelim for helping debug and fix.

Bug Good First Issue

Most helpful comment

hello! if no one started working on this yet, I can create the fix. ๐Ÿ’ญ

All 6 comments

This is also an issue (but maybe slightly different, I receive a "Forbidden" error) with a private PyPI registry that stores packages on S3 (without cloudfront). It returns a s3 URL (with temp auth token) with the message that the request is forbidden, whilst copying the URL and pasting it in a new browser initiates the correct download.

Downgrading to 1.0.10 solved this error, this error happens from version 1.1.x

@dvf thank you for the great issue report! :tada:

Regarding the fallback behaviour, I am reluctant to suggest we change at that at the moment since I think there are cases where authentication/authorsation is not available and a public package can still be added. Happy to discuss that and change behaviour in another issue. For this one, lets treat it as a bug and resolve it as such.

This is also an issue (but maybe slightly different, I receive a "Forbidden" error) with a private PyPI registry that stores packages on S3 (without cloudfront). It returns a s3 URL (with temp auth token) with the message that the request is forbidden, whilst copying the URL and pasting it in a new browser initiates the correct download.

@sschrijver think this was reported elsewhere, the issue here is that we use basic authentication as configured along with those requests. The existence of an "Authorization" header the "authorised" url ends up failing on the server side. IIRC, this was an issue with PyPI cloud since it deviates from the defined/expected behaviour for an index. See https://github.com/python-poetry/poetry/issues/3041#issuecomment-702506829 for that bit. I have not looked into the comments after that one yet. Additionally, note that there is the issue that using "authorised" urls will have other side-effects when the token used expires as these are used in the lock file.

hello! if no one started working on this yet, I can create the fix. ๐Ÿ’ญ

This also affects Sonatype Nexus PyPI repositories when using poetry 1.1.4, and downgrading to 1.0.10 fixes the issue there as well.

Was this page helpful?
0 / 5 - 0 ratings