Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] ContainerRegistry - bug with WWW-Authenticate header extraction #43585

Open
dragutint opened this issue Dec 24, 2024 · 0 comments
Open
Labels
customer-reported Issues that are reported by GitHub users external to the Azure organization. needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that

Comments

@dragutint
Copy link

Describe the bug
In the dependency azure-containers-containerregistry, issuing access token for the container registry API is not working in some edge-cases.
Response header WWW-Authenticate is used for extracting the realm, service, and scope.
The private method extractValue in the Java class ContainerRegistryCredentialsPolicy is not working properly when the container registry name contains one of the keywords: service or scope.

Exception or Stack Trace

Exception in thread "main" com.azure.core.exception.ClientAuthenticationException: Status code 401, "{"errors":[{"code":"UNAUTHORIZED","message":"authentication required, visit https://aka.ms/acr/authorization for more information.","detail":[{"Type":"registry","Name":"catalog","Action":"*"}]}]}
"
	at com.azure.containers.containerregistry.implementation.UtilsImpl.mapAcrErrorsException(UtilsImpl.java:334)
	at com.azure.containers.containerregistry.ContainerRegistryClient.listRepositoryNamesSinglePageSync(ContainerRegistryClient.java:136)
	at com.azure.containers.containerregistry.ContainerRegistryClient.lambda$listRepositoryNames$0(ContainerRegistryClient.java:124)
	at com.azure.core.http.rest.PagedIterable.lambda$new$3(PagedIterable.java:177)
	at com.azure.core.util.paging.ContinuablePagedByIteratorBase.requestPage(ContinuablePagedByIteratorBase.java:104)
	at com.azure.core.util.paging.ContinuablePagedByItemIterable$ContinuablePagedByItemIterator.<init>(ContinuablePagedByItemIterable.java:83)
	at com.azure.core.util.paging.ContinuablePagedByItemIterable.iterator(ContinuablePagedByItemIterable.java:58)
	at com.azure.core.util.paging.ContinuablePagedIterable.iterator(ContinuablePagedIterable.java:141)
	at java.base/java.lang.Iterable.forEach(Iterable.java:74)
	at com.atomdataservices.rico.infrastructure.azure.AzureContainerRegistryExample.main(AzureContainerRegistryExample.java:52)

To Reproduce
Name your container registry with word service or scope in the name, and try to list repository names using the SDK, you will receive the 401 Unauthorized exception above.

You can test it easily this way:

public class AzureContainerRegistryExample {

    public static void main(String[] args) {

        String registryEndpoint = "https://xxxservices.azurecr.io";

        ClientSecretCredential credential = new ClientSecretCredentialBuilder()
                .tenantId("tenant-id")
                .clientId("client-id")
                .clientSecret("client-secret")
                .build();

        ContainerRegistryClient client = new ContainerRegistryClientBuilder()
                .endpoint(registryEndpoint)
                .credential(credential)
                .buildClient();

        client.listRepositoryNames().forEach(System.out::println);
    }
}

Actually, the issuing of the access token for the CR will be skipped, here is the code snippet of the method in the ContainerRegistryCredentialsPolicy class:

    @Override
    public boolean authorizeRequestOnChallengeSync(HttpPipelineCallContext context, HttpResponse response) {
        String authHeader = response.getHeaderValue(WWW_AUTHENTICATE);
        if (!(response.getStatusCode() == 401 && authHeader != null)) {
            return false;
        } else {
            String scope =  extractValue(authHeader, SCOPES_PARAMETER);
            String serviceName = extractValue(authHeader, SERVICE_PARAMETER);

            if (scope != null && serviceName != null) {
                setAuthorizationHeaderSync(context, new ContainerRegistryTokenRequestContext(serviceName, scope));
                return true;
            }
        }

        return false;
    }

You can easily verify that extracting WWW-Authenticate response header is not working properly with the following example:
WWW-Authenticate = Bearer realm="https://xxxservices.azurecr.io/oauth2/token",service="xxxservices.azurecr.io",scope="registry:catalog:*"

Test the private method ContainerRegistryCredentialsPolicy.extractValue and you'll make sure that service is null. So, in the above code snippet issuing access token will be skipped.

Expected behavior
Authorization and issuing tokens for the CR is working properly regardless the container registry name.

Screenshots
The code from the ContainerRegistryCredentialsPolicy Java class
Image
The test from my machine:
Image

Setup (please complete the following information):

  • OS: MacOS
  • IDE: IntelliJ
  • Library/Libraries: com.azure:azure-containers-containerregistry:1.2.14
  • Java version: 21
  • App Server/Environment: Tomcat
  • Frameworks: Spring Boot
@github-actions github-actions bot added customer-reported Issues that are reported by GitHub users external to the Azure organization. needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that labels Dec 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
customer-reported Issues that are reported by GitHub users external to the Azure organization. needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that
Projects
None yet
Development

No branches or pull requests

1 participant