Skip to content

Add basic auth support to Maven download endpoints

David Fernandez requested to merge 212854-support-sbt-downloads into master

🌳 Context

The Maven Repository (docs) exposes a single download endpoint which is basically used to download files (be it .pom, .xml or .jar files).

Now, the Maven Repository can be accessed at 3 different levels:

  • project level. The url looks like: GET /api/v4/projects/:id/packages/maven/*path/:file_name.
  • group level. The url looks like: GET /api/v4/groups/:id/-/packages/maven/*path/:file_name.
  • instance level. The url looks like: GET GET /api/v4/packages/maven/*path/:file_name.

Effectively, we have 3 endpoints implemented but their logic is generally similar: check the credentials/permissions, locate the target package file and return it.

Regarding authentication, as documented, the Maven Repository only supports custom http headers.

The problem that we have is that we can have some clients of the Maven Repository, namely SBT, that doesn't support custom http headers. Instead, they support only basic auth. As such, $ sbt can't pull dependencies from a GitLab Maven Repository. This is blocking some users from using the Maven Repository as seen in An alternate way to download binary packages fr... (#212854 - closed).

🚑 The solution

Well, the solution is to allow all accepted token types (pat, deploy tokens and ci job tokens) to be sent through basic auth. This means that all 3 download endpoints will need to be updated for that.

Why change only the download endpoints? Awesome, that is a very good question.

As seen here, $ sbt allows uploading files to a Maven Repository. Unfortunately from what we have seen in local testing, it does it in a way that is not really compliant or better said expected by the backend. As such, we could have Maven Repository uploaded files that the backend will consider as incomplete or erroneous.

Applying the iteration value here, we're going to add support for $ sbt incrementally:

  1. first the download endpoints to allow pulling dependencies. (This MR).
  2. if needed, the upload endpoint to allow publishing files. We created Support artifacts upload from SBT (#408479 - closed) for that.

🔍 What does this MR do and why?

  1. Adds basic auth support to all download endpoints of the Maven Repository.
  2. Updates the relevant specs.
  3. Updates the relevant documentation.

🔭 Screenshots or screen recordings

No UI changes 😸

How to set up and validate locally

  1. Add a maven package that follows the naming convention. gl_pru can help here.

1️⃣ Using $ mvn

We're going to use $ mvn to assert that our changes has no impact on sending credentials with a custom header.

We're using

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>gl.pru</groupId>
  <artifactId>MyPackage</artifactId>
  <packaging>jar</packaging>
  <version>3.0.1</version>
  <name>MyPackage</name>
  <url>http://maven.apache.org</url>
  <properties>
    <maven.compiler.source>7</maven.compiler.source>
    <maven.compiler.target>7</maven.compiler.target>
  </properties>
  <dependencies>
    <dependency>
      <groupId>### package maven group id ###</groupId>
      <artifactId>### package maven artifact id ###</artifactId>
      <version>### package version ###</version>
    </dependency>
  </dependencies>
  <repositories>
    <repository>
      <id>gitlab-maven</id>
      <url>### endpoint_url ###</url>
    </repository>
  </repositories>
</project>
settings.xml
<?xml version="1.0" encoding="utf-8"?>
<settings>
  <servers>
    <server>
      <id>gitlab</id>
      <configuration>
        <httpHeaders>
          <property>
            <name>### token name, see https://docs.gitlab.com/ee/user/packages/maven_repository/#edit-the-settingsxml ###</name>
            <value>### token value ###</value>
          </property>
        </httpHeaders>
      </configuration>
    </server>
  </servers>
</settings>

We will pull the dependency with

$ mvn compile -s settings.xml

Results

Project level endpoint:

token type result
PAT
deploy token
ci job token

Group level endpoint:

token type result
PAT
deploy token
ci job token

Instance level endpoint:

token type result
PAT
deploy token
ci job token

All cases are working! 🎉

2️⃣ Using $ sbt

Let's see how things go with sbt.

We're using

build.sbt
import Dependencies._

ThisBuild / scalaVersion     := "2.12.8"
ThisBuild / version          := "1.5.10"
ThisBuild / organization     := "com.example"
ThisBuild / organizationName := "example"

lazy val root = (project in file("."))
  .settings(
    name := "hello",
    libraryDependencies += scalaTest % Test
  )

libraryDependencies += "<package maven group id>" % "<package maven artifact id>" % "<package version>"

resolvers += ("gitlab" at "<endpoint url>").withAllowInsecureProtocol(true)

credentials += Credentials("GitLab Packages Registry", "gdk.test", "<token name>", "<token>")

We will pull the dependency with

$ sbt compile

Results

Project level endpoint:

token type result
PAT
deploy token
ci job token

Group level endpoint:

token type result
PAT
deploy token
ci job token

Instance level endpoint:

token type result
PAT
deploy token
ci job token

$ sbt was able to pull the dependency in all cases! 🎉

🔮 Conclusions

This MR is working as expected

🚥 MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by David Fernandez

Merge request reports