Skip to content

Fix how maven dependency proxy credentials are sent

🔭 Context

The Maven dependency proxy is a feature where users can put the GitLab instance in the middle between package manager clients and (upstream) registries:

We are looking to the dependency proxy for maven packages:

$ mvn <-> GitLab <-> Maven compatible registry

Since, GitLab is located in the middle, we take this opportunity to "cache" the responses going through so that when the exact same request is received we can reply back with the cached version.

To make sure that the cached version is the same one as the upstream registry, we HEAD the registry.

The upstream registry can be public or private which means that users can pass credentials. In case of Maven registries, credentials are passed using Basic Auth (username+password).

In Maven dependency proxy: invalid urls in HEADs (#471052), it has been found out that we have an issue when the username contains the @ character. The problem was identified in the logic that checks the upstream registry. In this logic, we inline the basic auth credentials in the upstream url (example: https://<username>:<password>@<upstream url>). The problem with the inline approach is that if we have an @ in the username (or even password actually), we could have http clients that gets confused. It seems that it's the case for the client used to check the upstream registry, we end up in a similar situation like:

URI.parse("http://me@email.com:password@test.org/test")

which ends up 💥

URI::InvalidURIError: bad URI(is not URI?): "http://me@email.com:password@test.org/test"

🤔 What does this MR do and why?

This MR changes how credentials are sent to upstream in the maven dependency proxy.

  • Generate the correct Authorization header when interacting with the upstream registry.
  • Remove the inline credentials from the upstream url generation logic.
  • Update the related specs.

🏎 MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

🌈 Screenshots or screen recordings

🤷 (No UI changes)

How to set up and validate locally

  1. Create a project.
  2. Have a PAT ready (maintainer+ level).
  3. Let's simulate a (dummy) upstream registry locally with sinatra:
    require 'sinatra'
    
    set :bind, 'gdk.test'
    
    use Rack::Auth::Basic,"Protected Area" do |username, password|
      username == 'user@test.com' && password == 'password'
    end
    
    get "/*" do
      "Hello World!"
    end
  4. In the project settings, Packages and registries settings, enable the maven dependency proxy with:
  • url: http://gdk.test:4567
  • username: user@test.com
  • password: password

All ready! 🚀

Now, let's pull a file through the maven dependency proxy. We're going to use $ curl to simulate that request.

$ curl "http://<username>:<pat>@gdk.test:8000/api/v4/projects/<project_id>/dependency_proxy/packages/maven/gl/pru/My.Ananas/13.0.3/My.Ananas-13.0.3.pom"

This very first request will succeed and create the cached version on GitLab. You can see it in the Package Registry (under the Deploy menu).

Let's request it again (second time).

On master

$ curl "http://<username>:<pat>@gdk.test:8000/api/v4/projects/<project_id>/dependency_proxy/packages/maven/gl/pru/My.Ananas/13.0.3/My.Ananas-13.0.3.pom"
{"message":"500 Internal Server Error"}

The 💥 comes from the URI.parse failing.

With this MR

$ curl "http://<username>:<pat>@gdk.test:8000/api/v4/projects/<project_id>/dependency_proxy/packages/maven/gl/pru/My.Ananas/13.0.3/My.Ananas-13.0.3.pom"
Hello World!

Fixed! 🎉

Edited by David Fernandez

Merge request reports