diff --git a/conans/client/rest/rest_client.py b/conans/client/rest/rest_client.py index 2b8e8fc401f..ed1ddd06d65 100644 --- a/conans/client/rest/rest_client.py +++ b/conans/client/rest/rest_client.py @@ -1,7 +1,7 @@ from conans import CHECKSUM_DEPLOY, REVISIONS, ONLY_V2, OAUTH_TOKEN from conans.client.rest.rest_client_v1 import RestV1Methods from conans.client.rest.rest_client_v2 import RestV2Methods -from conans.errors import OnlyV2Available +from conans.errors import OnlyV2Available, AuthenticationException from conans.search.search import filter_packages from conans.util.log import logger @@ -95,7 +95,13 @@ def authenticate(self, user, password): if self.refresh_token and self.token: token, refresh_token = api_v1.refresh_token(self.token, self.refresh_token) else: - if self._capable(OAUTH_TOKEN): + try: + # Check capabilities can raise also 401 until the new Artifactory is released + oauth_capable = self._capable(OAUTH_TOKEN) + except AuthenticationException: + oauth_capable = False + + if oauth_capable: # Artifactory >= 6.13.X token, refresh_token = api_v1.authenticate_oauth(user, password) else: diff --git a/conans/test/functional/remote/auth_test.py b/conans/test/functional/remote/auth_test.py index 5b0176493ea..347eedd86e3 100644 --- a/conans/test/functional/remote/auth_test.py +++ b/conans/test/functional/remote/auth_test.py @@ -1,10 +1,14 @@ import os import unittest +from requests.models import Response + from conans.client import tools +from conans.errors import AuthenticationException from conans.model.ref import ConanFileReference from conans.paths import CONANFILE -from conans.test.utils.tools import TestClient, TestServer +from conans.test.utils.tools import TestClient +from conans.test.utils.tools import TestServer from conans.util.files import save conan_content = """ @@ -119,3 +123,33 @@ def no_client_username_checks_test(self): # Check that login failed once before ok self.assertEqual(self.conan.api.app.user_io.login_index["default"], 2) + + +class AuthenticationTest(unittest.TestCase): + + def unauthorized_during_capabilities_test(self): + + class RequesterMock(object): + + def __init__(self, *args, **kwargs): + pass + + def get(self, url, *args, **kwargs): + if "authenticate" in url: + resp_basic_auth = Response() + resp_basic_auth._content = b"TOKEN" + resp_basic_auth.status_code = 200 + resp_basic_auth.headers = {"Content-Type": "text/plain"} + return resp_basic_auth + + if "ping" in url and not kwargs["auth"].token: + raise AuthenticationException( + "I'm an Artifactory without anonymous access that " + "requires authentication for the ping endpoint and " + "I don't return the capabilities") + raise Exception("Shouldn't be more remote calls") + + self.client = TestClient(requester_class=RequesterMock, default_server_user=True) + self.client.run("user user -p password -r default") + self.assertIn("Changed user of remote 'default' from 'None' (anonymous) to 'user'", + self.client.out)