Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sdk/identity/azure-identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
### Bugs Fixed

### Other Changes

- VisualStudioCodeCredential prints an informative error message when used (as it is currently broken) ([#30385](https://github.com/Azure/azure-sdk-for-python/pull/30385))
- Removed dependency on `six`. ([#30613](https://github.com/Azure/azure-sdk-for-python/pull/30613))

## 1.13.0 (2023-05-11)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import subprocess
import sys
from typing import Any, Dict, List, Optional
import six

from azure.core.credentials import AccessToken
from azure.core.exceptions import ClientAuthenticationError
Expand Down Expand Up @@ -206,8 +205,8 @@ def _run_command(command: str, timeout: int) -> str:
except OSError as ex:
# failed to execute 'cmd' or '/bin/sh'
error = CredentialUnavailableError(message="Failed to execute '{}'".format(args[0]))
six.raise_from(error, ex)
raise error from ex
except Exception as ex: # pylint:disable=broad-except
# could be a timeout, for example
error = CredentialUnavailableError(message="Failed to invoke the Azure Developer CLI")
six.raise_from(error, ex)
raise error from ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import sys
import time
from typing import List, Optional, Any, Dict
import six

from azure.core.credentials import AccessToken
from azure.core.exceptions import ClientAuthenticationError
Expand Down Expand Up @@ -184,8 +183,8 @@ def _run_command(command: str, timeout: int) -> str:
except OSError as ex:
# failed to execute 'cmd' or '/bin/sh'
error = CredentialUnavailableError(message="Failed to execute '{}'".format(args[0]))
six.raise_from(error, ex)
raise error from ex
except Exception as ex: # pylint:disable=broad-except
# could be a timeout, for example
error = CredentialUnavailableError(message="Failed to invoke the Azure CLI")
six.raise_from(error, ex)
raise error from ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import subprocess
import sys
from typing import List, Tuple, Optional, Any
import six

from azure.core.credentials import AccessToken
from azure.core.exceptions import ClientAuthenticationError
Expand Down Expand Up @@ -135,7 +134,7 @@ def run_command_line(command_line: List[str], timeout: int) -> str:
message="Failed to invoke PowerShell.\n"
"To mitigate this issue, please refer to the troubleshooting guidelines here at "
"https://aka.ms/azsdk/python/identity/powershellcredential/troubleshoot.")
six.raise_from(error, ex)
raise error from ex

raise_for_error(proc.returncode, stdout, stderr)
return stdout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
from cryptography.hazmat.backends import default_backend
import six

from .._internal import validate_tenant_id
from .._internal.client_credential_base import ClientCredentialBase
Expand Down Expand Up @@ -118,7 +117,7 @@ def load_pkcs12_certificate(
)
except ValueError as ex:
# mentioning PEM here because we raise this error when certificate_data is garbage
six.raise_from(ValueError("Failed to deserialize certificate in PEM or PKCS12 format"), ex)
raise ValueError("Failed to deserialize certificate in PEM or PKCS12 format") from ex
if not private_key:
raise ValueError("The certificate must include its private key")
if not cert:
Expand Down Expand Up @@ -154,8 +153,9 @@ def get_client_credential(
raise ValueError('CertificateCredential requires a value for either "certificate_path" or "certificate_data"')

if password:
# if password is already bytes, this won't change its encoding
password = six.ensure_binary(password, "utf-8")
# if password is already bytes, no need to encode.
if isinstance(password, str):
password = password.encode("utf-8")
password = cast("Optional[bytes]", password)

if b"-----BEGIN" in certificate_data:
Expand All @@ -175,9 +175,9 @@ def get_client_credential(
try:
# the JWT needs the whole chain but load_pem_x509_certificate deserializes only the signing cert
chain = extract_cert_chain(cert.pem_bytes)
client_credential["public_certificate"] = six.ensure_str(chain)
client_credential["public_certificate"] = chain.decode("utf-8")
except ValueError as ex:
# we shouldn't land here--cryptography already loaded the cert and would have raised if it were malformed
six.raise_from(ValueError("Malformed certificate"), ex)
raise ValueError("Malformed certificate") from ex

return client_credential
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import os
from typing import Any, Optional, Dict

import six

from azure.core.exceptions import ClientAuthenticationError, HttpResponseError
from azure.core.pipeline.transport import HttpRequest
from azure.core.credentials import AccessToken
Expand Down Expand Up @@ -83,7 +81,7 @@ def _request_token(self, *scopes: str, **kwargs: Any) -> AccessToken:
self._error_message = (
"ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint."
)
six.raise_from(CredentialUnavailableError(self._error_message), ex)
raise CredentialUnavailableError(self._error_message) from ex

if not self._endpoint_available:
raise CredentialUnavailableError(self._error_message)
Expand All @@ -100,8 +98,8 @@ def _request_token(self, *scopes: str, **kwargs: Any) -> AccessToken:
self._error_message += "The requested identity has not been assigned to this resource."
else:
self._error_message += "No identity has been assigned to this resource."
six.raise_from(CredentialUnavailableError(message=self._error_message), ex)
raise CredentialUnavailableError(message=self._error_message) from ex

# any other error is unexpected
six.raise_from(ClientAuthenticationError(message=ex.message, response=ex.response), ex)
raise ClientAuthenticationError(message=ex.message, response=ex.response) from ex
return token
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import time
from typing import Any, Optional

import six
import msal

from azure.core.credentials import AccessToken
Expand Down Expand Up @@ -89,7 +88,7 @@ def __init__(
message = (
'"client_certificate" is not a valid certificate in PEM or PKCS12 format'
)
six.raise_from(ValueError(message), ex)
raise ValueError(message) from ex
elif client_secret:
credential = client_secret
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from uuid import uuid4
from typing import TYPE_CHECKING, List, Any, Iterable, Optional, Union, Dict

import six
from msal import TokenCache

from azure.core.pipeline import PipelineResponse
Expand Down Expand Up @@ -208,22 +207,15 @@ def _get_jwt_assertion_request(

def _get_client_certificate_assertion(self, certificate: AadClientCertificate, **kwargs: Any) -> str:
now = int(time.time())
header = six.ensure_binary(
json.dumps({"typ": "JWT", "alg": "RS256", "x5t": certificate.thumbprint}), encoding="utf-8"
)
payload = six.ensure_binary(
json.dumps(
{
"jti": str(uuid4()),
"aud": self._get_token_url(**kwargs),
"iss": self._client_id,
"sub": self._client_id,
"nbf": now,
"exp": now + (60 * 30),
}
),
encoding="utf-8",
)
header = json.dumps({"typ": "JWT", "alg": "RS256", "x5t": certificate.thumbprint}).encode("utf-8")
payload = json.dumps({
"jti": str(uuid4()),
"aud": self._get_token_url(**kwargs),
"iss": self._client_id,
"sub": self._client_id,
"nbf": now,
"exp": now + (60 * 30),
}).encode("utf-8")
jws = base64.urlsafe_b64encode(header) + b"." + base64.urlsafe_b64encode(payload)
signature = certificate.sign(jws)
jwt_bytes = jws + b"." + base64.urlsafe_b64encode(signature)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
from cryptography.hazmat.backends import default_backend
import six


class AadClientCertificate:
Expand All @@ -30,7 +29,7 @@ def __init__(

cert = x509.load_pem_x509_certificate(pem_bytes, default_backend())
fingerprint = cert.fingerprint(hashes.SHA1()) # nosec
self._thumbprint = six.ensure_str(base64.urlsafe_b64encode(fingerprint), encoding="utf-8")
self._thumbprint = base64.urlsafe_b64encode(fingerprint).decode("utf-8")

@property
def thumbprint(self) -> str:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import json
import base64

from six import raise_from
from azure.core.exceptions import ClientAuthenticationError

from .utils import within_credential_chain
Expand Down Expand Up @@ -76,6 +75,6 @@ def wrapper(*args, **kwargs):
raise
except Exception as ex: # pylint:disable=broad-except
auth_error = ClientAuthenticationError(message="Authentication failed: {}".format(ex))
raise_from(auth_error, ex)
raise auth_error from ex

return wrapper
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import logging
import time
from typing import Any, Optional
import six
from urllib.parse import urlparse

from azure.core.credentials import AccessToken
from azure.core.exceptions import ClientAuthenticationError
Expand Down Expand Up @@ -55,7 +55,7 @@ def _build_auth_record(response):
home_account_id = id_token["sub"]

# "iss" is the URL of the issuing tenant e.g. https://authority/tenant
issuer = six.moves.urllib_parse.urlparse(id_token["iss"])
issuer = urlparse(id_token["iss"])

# tenant which issued the token, not necessarily user's home tenant
tenant_id = id_token.get("tid") or issuer.path.strip("/")
Expand All @@ -74,7 +74,7 @@ def _build_auth_record(response):
auth_error = ClientAuthenticationError(
message="Failed to build AuthenticationRecord from unexpected identity token"
)
six.raise_from(auth_error, ex)
raise auth_error from ex


class InteractiveCredential(MsalCredential, ABC):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from typing import Any, Callable, Dict, Optional

from msal import TokenCache
import six

from azure.core.credentials import AccessToken
from azure.core.exceptions import ClientAuthenticationError, DecodeError
Expand Down Expand Up @@ -47,7 +46,7 @@ def _process_response(self, response: PipelineResponse, request_time: int) -> Ac
message = "Failed to deserialize JSON from response"
else:
message = 'Unexpected content type "{}"'.format(response.http_response.content_type)
six.raise_from(ClientAuthenticationError(message=message, response=response.http_response), ex)
raise ClientAuthenticationError(message=message, response=response.http_response) from ex

if not content:
raise ClientAuthenticationError(message="No token received.", response=response.http_response)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# ------------------------------------
import threading
from typing import Any, Dict, Optional, Union
import six

from azure.core.exceptions import ClientAuthenticationError
from azure.core.pipeline.policies import ContentDecodePolicy
Expand Down Expand Up @@ -84,8 +83,8 @@ def post(
if isinstance(data, dict):
request.headers["Content-Type"] = "application/x-www-form-urlencoded"
request.set_formdata_body(data)
elif isinstance(data, six.text_type):
body_bytes = six.ensure_binary(data)
elif isinstance(data, str):
body_bytes = data.encode("utf-8")
request.set_bytes_body(body_bytes)
else:
raise ValueError('expected "data" to be text or a dict')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import time
from typing import Any, Iterable, List, Mapping, Optional, cast
from urllib.parse import urlparse
import six
import msal

from azure.core.credentials import AccessToken
Expand Down Expand Up @@ -195,7 +194,7 @@ def _get_cached_access_token(self, scopes: Iterable[str], account: CacheItem) ->
return AccessToken(token["secret"], expires_on)
except Exception as ex: # pylint:disable=broad-except
message = "Error accessing cached data: {}".format(ex)
six.raise_from(CredentialUnavailableError(message=message), ex)
raise CredentialUnavailableError(message=message) from ex

return None

Expand All @@ -210,7 +209,7 @@ def _get_refresh_tokens(self, account):
return [token["secret"] for token in cache_entries if "secret" in token]
except Exception as ex: # pylint:disable=broad-except
message = "Error accessing cached data: {}".format(ex)
six.raise_from(CredentialUnavailableError(message=message), ex)
raise CredentialUnavailableError(message=message) from ex

@staticmethod
def supported() -> bool:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import sys
from typing import TYPE_CHECKING, Any

import six

if TYPE_CHECKING:
import msal_extensions

Expand Down Expand Up @@ -107,7 +105,7 @@ def _get_persistence(allow_unencrypted, account_name, cache_name):
+ ' more information. Specify "allow_unencrypted_storage=True" to store the cache unencrypted'
+ " instead of raising this exception."
)
six.raise_from(error, ex)
raise error from ex
return msal_extensions.FilePersistence(file_path)

raise NotImplementedError("A persistent cache is not available in this environment.")
1 change: 0 additions & 1 deletion sdk/identity/azure-identity/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,5 @@
"cryptography>=2.5",
"msal<2.0.0,>=1.20.0",
"msal-extensions<2.0.0,>=0.3.0",
"six>=1.12.0",
],
)
15 changes: 7 additions & 8 deletions sdk/identity/azure-identity/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

from unittest import mock
import pytest
import six
from devtools_testutils import test_proxy, add_general_regex_sanitizer, is_live, add_body_key_sanitizer
from azure.identity._constants import DEVELOPER_SIGN_ON_CLIENT_ID, EnvironmentVariables

Expand Down Expand Up @@ -78,9 +77,9 @@ def get_certificate_parameters(content, password_protected_content, password, ex
# type: (bytes, bytes, str, str) -> dict
current_directory = os.path.dirname(__file__)
parameters = {
"cert_bytes": six.ensure_binary(content),
"cert_bytes": content,
"cert_path": os.path.join(current_directory, "certificate." + extension),
"cert_with_password_bytes": six.ensure_binary(password_protected_content),
"cert_with_password_bytes": password_protected_content,
"cert_with_password_path": os.path.join(current_directory, "certificate-with-password." + extension),
"password": password,
}
Expand All @@ -103,7 +102,8 @@ def live_pem_certificate(live_service_principal):
password = os.environ.get("CERTIFICATE_PASSWORD")

if content and password_protected_content and password:
parameters = get_certificate_parameters(content, password_protected_content, password, "pem")
parameters = get_certificate_parameters(
content.encode("utf-8"), password_protected_content.encode("utf-8"), password, "pem")
return dict(live_service_principal, **parameters)

pytest.skip("Missing PEM certificate configuration")
Expand All @@ -118,9 +118,8 @@ def live_pfx_certificate(live_service_principal):

if encoded_content and encoded_password_protected_content and password:
import base64

content = base64.b64decode(six.ensure_binary(encoded_content))
password_protected_content = base64.b64decode(six.ensure_binary(encoded_password_protected_content))
content = base64.b64decode(encoded_content.encode("utf-8"))
password_protected_content = base64.b64decode(encoded_password_protected_content.encode("utf-8"))

parameters = get_certificate_parameters(content, password_protected_content, password, "pfx")
return dict(live_service_principal, **parameters)
Expand Down Expand Up @@ -174,7 +173,7 @@ def add_sanitizers(test_proxy):
add_general_regex_sanitizer(regex=user_assigned_identity_client_id, value=PLAYBACK_CLIENT_ID)
if "CAE_ARM_URL" in os.environ and "CAE_TENANT_ID" in os.environ and "CAE_USERNAME" in os.environ:
try:
from six.moves.urllib_parse import urlparse
from urllib.parse import urlparse
arm_url = os.environ["CAE_ARM_URL"]
real = urlparse(arm_url)
add_general_regex_sanitizer(regex=real.netloc, value="management.azure.com")
Expand Down
Loading