Gracefully handle blank spaces in scope query params for the container registry /jwt/auth requests
Context
Related to Container Registry OCI Conformance (&10345 - closed). This was found to be the root cause for POST request to mount another repository's blob... (container-registry#1092 - moved).
Problem
Please see #425045 (comment 1556904912) for a detailed breakdown. The short version below should suffice though:
When making requests against the /jwt/auth
endpoint of the Rails API (which must happen prior to making read/write requests against the container registry), clients send several query params, among which scope
. The scope
is usually comprised of a single value, as the vast majority of requests target a single repository. The format of this scope
param looks like this:
repository:<path to container registry repository>:<operation(s) that a user is requesting permissions to>
And an example, when a token with pull
and push
permissions for the gitlab-com/registry-oci-conformance/repo-b
container repository is being requested:
repository:gitlab-com/registry-oci-conformance/repo-b:pull,push
However, there is one type of registry operation (cross repository blob mounts) that require permissions for two separate repositories (the origin and the destination repositories for the blob mount). In those cases, we observe that most clients (like Docker) will use multiple scope
params, one per repository, while others (like go-containerregistry
) will use a single scope
param with multiple values separated by a blank space.
For example, when mounting a blob from repo-a
to repo-b
, Docker will set the scope
params as follows:
?scope="repository:repo-a:pull"&scope="repository:repo-b:push,pull"
While go-containerregistry
will do:
?scope="repository:repo-a:pull repository:repo-b:push,pull"
The former is correct per the Docker Token Authentication Specification. The latter is also correct, but per RFC6749.
Right now, what's happening is that Rails discards whatever comes after the blank space in the scope
param, which leads to a failure on the client side (for those that behave as go-containerregistry
) as the token does not have the required permissions.
Solution
We should update the Rails logic for the container registry /jwt/auth
requests so that it handles blank spaces gracefully, and splits the content of scope
by blank space (if any). In summary, we expect the exact same behaviour and results regardless if the client sent a single scope
with multiple values separated by a blank space or multiple scope
parameters.