diff --git a/src/google/adk/tools/openapi_tool/auth/auth_helpers.py b/src/google/adk/tools/openapi_tool/auth/auth_helpers.py index e8eba69a94..cc8464d997 100644 --- a/src/google/adk/tools/openapi_tool/auth/auth_helpers.py +++ b/src/google/adk/tools/openapi_tool/auth/auth_helpers.py @@ -14,6 +14,8 @@ from __future__ import annotations +import base64 + from typing import Any from typing import Dict from typing import List @@ -387,16 +389,25 @@ def credential_to_param( } return param, kwargs elif ( - auth_credential - and auth_credential.http + auth_credential.http + and auth_credential.http.scheme.lower() == "basic" and auth_credential.http.credentials - and ( - auth_credential.http.credentials.username - or auth_credential.http.credentials.password - ) + and auth_credential.http.credentials.username is not None + and auth_credential.http.credentials.password is not None ): - # Basic Auth is explicitly NOT supported - raise NotImplementedError("Basic Authentication is not supported.") + credentials = auth_credential.http.credentials + encoded_credentials = base64.b64encode( + f"{credentials.username}:{credentials.password}".encode("utf-8") + ).decode("ascii") + param = ApiParameter( + original_name="Authorization", + param_location="header", + param_schema=Schema(type="string"), + description=auth_scheme.description or "Basic authentication", + py_name=INTERNAL_AUTH_PREFIX + "Authorization", + ) + kwargs = {param.py_name: f"Basic {encoded_credentials}"} + return param, kwargs else: raise ValueError("Invalid HTTP auth credentials") diff --git a/tests/unittests/tools/openapi_tool/auth/test_auth_helper.py b/tests/unittests/tools/openapi_tool/auth/test_auth_helper.py index 3f5e8f07b5..fe9be5a7ab 100644 --- a/tests/unittests/tools/openapi_tool/auth/test_auth_helper.py +++ b/tests/unittests/tools/openapi_tool/auth/test_auth_helper.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import base64 from unittest.mock import patch from fastapi.openapi.models import APIKey @@ -411,7 +412,7 @@ def test_credential_to_param_http_bearer(): assert kwargs == {INTERNAL_AUTH_PREFIX + "Authorization": "Bearer test_token"} -def test_credential_to_param_http_basic_not_supported(): +def test_credential_to_param_http_basic(): auth_scheme = HTTPBase(scheme="basic") auth_credential = AuthCredential( auth_type=AuthCredentialTypes.HTTP, @@ -421,9 +422,27 @@ def test_credential_to_param_http_basic_not_supported(): ), ) - with pytest.raises( - NotImplementedError, match="Basic Authentication is not supported." - ): + param, kwargs = credential_to_param(auth_scheme, auth_credential) + + expected_credentials = base64.b64encode(b"user:password").decode("ascii") + assert param.original_name == "Authorization" + assert param.param_location == "header" + assert kwargs == { + INTERNAL_AUTH_PREFIX + "Authorization": f"Basic {expected_credentials}" + } + + +def test_credential_to_param_http_basic_missing_password(): + auth_scheme = HTTPBase(scheme="basic") + auth_credential = AuthCredential( + auth_type=AuthCredentialTypes.HTTP, + http=HttpAuth( + scheme="basic", + credentials=HttpCredentials(username="user"), + ), + ) + + with pytest.raises(ValueError, match="Invalid HTTP auth credentials"): credential_to_param(auth_scheme, auth_credential)