Skip to content

Commit

Permalink
Rename CertificateCredential's certificate_bytes -> certificate_data (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
chlowell authored Mar 4, 2021
1 parent b432ace commit 52406b6
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 25 deletions.
6 changes: 5 additions & 1 deletion sdk/identity/azure-identity/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Release History

## 1.6.0b2 (Unreleased)

### Breaking Changes
> These changes do not impact the API of stable versions such as 1.5.0.
> Only code written against a beta version such as 1.6.0b1 may be affected.
- Renamed `CertificateCredential` keyword argument `certificate_bytes` to
`certificate_data`

## 1.6.0b1 (2021-02-09)
### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ class CertificateCredential(ClientCredentialBase):
:param str tenant_id: ID of the service principal's tenant. Also called its 'directory' ID.
:param str client_id: the service principal's client ID
:param str certificate_path: path to a PEM-encoded certificate file including the private key. If not provided,
`certificate_bytes` is required.
`certificate_data` is required.
:keyword str authority: Authority of an Azure Active Directory endpoint, for example 'login.microsoftonline.com',
the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts`
defines authorities for other clouds.
:keyword bytes certificate_bytes: the bytes of a certificate in PEM format, including the private key
:keyword bytes certificate_data: the bytes of a certificate in PEM format, including the private key
:keyword password: The certificate's password. If a unicode string, it will be encoded as UTF-8. If the certificate
requires a different encoding, pass appropriately encoded bytes instead.
:paramtype password: str or bytes
Expand Down Expand Up @@ -68,34 +68,34 @@ def extract_cert_chain(pem_bytes):
return b"".join(chain.splitlines())


def get_client_credential(certificate_path, password=None, certificate_bytes=None, send_certificate_chain=False, **_):
def get_client_credential(certificate_path, password=None, certificate_data=None, send_certificate_chain=False, **_):
# type: (Optional[str], Optional[Union[bytes, str]], Optional[bytes], bool, **Any) -> dict
"""Load a certificate from a filesystem path or bytes, return it as a dict suitable for msal.ClientApplication"""

if certificate_path:
with open(certificate_path, "rb") as f:
certificate_bytes = f.read()
elif not certificate_bytes:
raise ValueError('CertificateCredential requires a value for "certificate_path" or "certificate_bytes"')
certificate_data = f.read()
elif not certificate_data:
raise ValueError('CertificateCredential requires a value for "certificate_path" or "certificate_data"')

if isinstance(password, six.text_type):
password = password.encode(encoding="utf-8")

private_key = serialization.load_pem_private_key(certificate_bytes, password=password, backend=default_backend())
private_key = serialization.load_pem_private_key(certificate_data, password=password, backend=default_backend())
if not isinstance(private_key, RSAPrivateKey):
raise ValueError("CertificateCredential requires an RSA private key because it uses RS256 for signing")

cert = x509.load_pem_x509_certificate(certificate_bytes, default_backend())
cert = x509.load_pem_x509_certificate(certificate_data, default_backend())
fingerprint = cert.fingerprint(hashes.SHA1()) # nosec

client_credential = {"private_key": certificate_bytes, "thumbprint": hexlify(fingerprint).decode("utf-8")}
client_credential = {"private_key": certificate_data, "thumbprint": hexlify(fingerprint).decode("utf-8")}
if password:
client_credential["passphrase"] = password

if send_certificate_chain:
try:
# the JWT needs the whole chain but load_pem_x509_certificate deserializes only the signing cert
chain = extract_cert_chain(certificate_bytes)
chain = extract_cert_chain(certificate_data)
client_credential["public_certificate"] = six.ensure_str(chain)
except ValueError as ex:
# we shouldn't land here--cryptography already loaded the cert and would have raised if it were malformed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ class CertificateCredential(AsyncContextManager):
:param str tenant_id: ID of the service principal's tenant. Also called its 'directory' ID.
:param str client_id: the service principal's client ID
:param str certificate_path: path to a PEM-encoded certificate file including the private key. If not provided,
`certificate_bytes` is required.
`certificate_data` is required.
:keyword str authority: Authority of an Azure Active Directory endpoint, for example 'login.microsoftonline.com',
the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts`
defines authorities for other clouds.
:keyword bytes certificate_bytes: the bytes of a certificate in PEM format, including the private key
:keyword bytes certificate_data: the bytes of a certificate in PEM format, including the private key
:keyword password: The certificate's password. If a unicode string, it will be encoded as UTF-8. If the certificate
requires a different encoding, pass appropriately encoded bytes instead.
:paramtype password: str or bytes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def test_non_rsa_key():
with pytest.raises(ValueError, match=".*RS256.*"):
CertificateCredential("tenant-id", "client-id", EC_CERT_PATH)
with pytest.raises(ValueError, match=".*RS256.*"):
CertificateCredential("tenant-id", "client-id", certificate_bytes=open(EC_CERT_PATH, "rb").read())
CertificateCredential("tenant-id", "client-id", certificate_data=open(EC_CERT_PATH, "rb").read())


def test_tenant_id_validation():
Expand Down Expand Up @@ -145,9 +145,9 @@ def test_requires_certificate():
with pytest.raises(ValueError):
CertificateCredential("tenant", "client-id", certificate_path="")
with pytest.raises(ValueError):
CertificateCredential("tenant", "client-id", certificate_bytes=None)
CertificateCredential("tenant", "client-id", certificate_data=None)
with pytest.raises(ValueError):
CertificateCredential("tenant", "client-id", certificate_path="", certificate_bytes=None)
CertificateCredential("tenant", "client-id", certificate_path="", certificate_data=None)


@pytest.mark.parametrize("cert_path,cert_password", BOTH_CERTS)
Expand Down Expand Up @@ -190,7 +190,7 @@ def mock_send(request, **kwargs):
cred = CertificateCredential(
tenant_id,
client_id,
certificate_bytes=cert_bytes,
certificate_data=cert_bytes,
password=cert_password,
transport=Mock(send=mock_send),
authority=authority,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def test_non_rsa_key():
with pytest.raises(ValueError, match=".*RS256.*"):
CertificateCredential("tenant-id", "client-id", EC_CERT_PATH)
with pytest.raises(ValueError, match=".*RS256.*"):
CertificateCredential("tenant-id", "client-id", certificate_bytes=open(EC_CERT_PATH, "rb").read())
CertificateCredential("tenant-id", "client-id", certificate_data=open(EC_CERT_PATH, "rb").read())


def test_tenant_id_validation():
Expand Down Expand Up @@ -141,9 +141,9 @@ def test_requires_certificate():
with pytest.raises(ValueError):
CertificateCredential("tenant", "client-id", certificate_path="")
with pytest.raises(ValueError):
CertificateCredential("tenant", "client-id", certificate_bytes=None)
CertificateCredential("tenant", "client-id", certificate_data=None)
with pytest.raises(ValueError):
CertificateCredential("tenant", "client-id", certificate_path="", certificate_bytes=None)
CertificateCredential("tenant", "client-id", certificate_path="", certificate_data=None)


@pytest.mark.asyncio
Expand Down Expand Up @@ -177,7 +177,7 @@ async def mock_send(request, **kwargs):
cred = CertificateCredential(
tenant_id,
client_id,
certificate_bytes=cert_bytes,
certificate_data=cert_bytes,
password=cert_password,
transport=Mock(send=mock_send),
authority=authority,
Expand Down
4 changes: 2 additions & 2 deletions sdk/identity/azure-identity/tests/test_live.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ def test_certificate_credential(live_certificate):
)
get_token(credential)

credential = CertificateCredential(tenant_id, client_id, certificate_bytes=live_certificate["cert_bytes"])
credential = CertificateCredential(tenant_id, client_id, certificate_data=live_certificate["cert_bytes"])
get_token(credential)

credential = CertificateCredential(
tenant_id,
client_id,
certificate_bytes=live_certificate["cert_with_password_bytes"],
certificate_data=live_certificate["cert_with_password_bytes"],
password=live_certificate["password"],
)
get_token(credential)
Expand Down
4 changes: 2 additions & 2 deletions sdk/identity/azure-identity/tests/test_live_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ async def test_certificate_credential(live_certificate):
)
await get_token(credential)

credential = CertificateCredential(tenant_id, client_id, certificate_bytes=live_certificate["cert_bytes"])
credential = CertificateCredential(tenant_id, client_id, certificate_data=live_certificate["cert_bytes"])
await get_token(credential)

credential = CertificateCredential(
tenant_id,
client_id,
certificate_bytes=live_certificate["cert_with_password_bytes"],
certificate_data=live_certificate["cert_with_password_bytes"],
password=live_certificate["password"],
)
await get_token(credential)
Expand Down

0 comments on commit 52406b6

Please sign in to comment.