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
16 changes: 16 additions & 0 deletions sdk/identity/azure-identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@
`AZURE_CLIENT_ID` to configure a user-assigned managed identity.
([#10931](https://github.com/Azure/azure-sdk-for-python/issues/10931))

### Breaking Changes
- Removed application authentication APIs added in 1.4.0 beta versions. These
will be reintroduced in 1.5.0b1. Passing the keyword arguments below
generally won't cause a runtime error, but the arguments have no effect.
- Removed `authenticate` method from `DeviceCodeCredential`,
`InteractiveBrowserCredential`, and `UsernamePasswordCredential`
- Removed `allow_unencrypted_cache` and `enable_persistent_cache` keyword
arguments from `CertificateCredential`, `ClientSecretCredential`,
`DeviceCodeCredential`, `InteractiveBrowserCredential`, and
`UsernamePasswordCredential`
- Removed `disable_automatic_authentication` keyword argument from
`DeviceCodeCredential` and `InteractiveBrowserCredential`
- Removed `allow_unencrypted_cache` keyword argument from
`SharedTokenCacheCredential`
- Removed classes `AuthenticationRecord` and `AuthenticationRequiredError`
- Removed `identity_config` keyword argument from `ManagedIdentityCredential`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to describe more on the effect?
e.g. those kwargs will be ignored or will cause exception?


## 1.4.0b7 (2020-07-22)
- `DefaultAzureCredential` has a new optional keyword argument,
Expand Down
1 change: 0 additions & 1 deletion sdk/identity/azure-identity/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
recursive-include samples *.py
recursive-include tests *.py
include *.md
include azure/__init__.py
5 changes: 1 addition & 4 deletions sdk/identity/azure-identity/azure/identity/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
# ------------------------------------
"""Credentials for Azure SDK clients."""

from ._auth_record import AuthenticationRecord
from ._exceptions import AuthenticationRequiredError, CredentialUnavailableError
from ._exceptions import CredentialUnavailableError
from ._constants import AzureAuthorityHosts, KnownAuthorities
from ._credentials import (
AzureCliCredential,
Expand All @@ -25,8 +24,6 @@


__all__ = [
"AuthenticationRecord",
"AuthenticationRequiredError",
"AuthorizationCodeCredential",
"AzureAuthorityHosts",
"AzureCliCredential",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@ class InteractiveBrowserCredential(InteractiveCredential):
authenticate work or school accounts.
:keyword str client_id: Client ID of the Azure Active Directory application users will sign in to. If
unspecified, the Azure CLI's ID will be used.
:keyword AuthenticationRecord authentication_record: :class:`AuthenticationRecord` returned by :func:`authenticate`
:keyword bool disable_automatic_authentication: if True, :func:`get_token` will raise
:class:`AuthenticationRequiredError` when user interaction is required to acquire a token. Defaults to False.
:keyword bool enable_persistent_cache: if True, the credential will store tokens in a persistent cache shared by
other user credentials. Defaults to False.
:keyword bool allow_unencrypted_cache: if True, the credential will fall back to a plaintext cache on platforms
where encryption is unavailable. Default to False. Has no effect when `enable_persistent_cache` is False.
:keyword int timeout: seconds to wait for the user to complete authentication. Defaults to 300 (5 minutes).
"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ class CertificateCredential(CertificateCredentialBase):
: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
:keyword bool enable_persistent_cache: if True, the credential will store tokens in a persistent cache. Defaults to
False.
:keyword bool allow_unencrypted_cache: if True, the credential will fall back to a plaintext cache when encryption
is unavailable. Default to False. Has no effect when `enable_persistent_cache` is False.
"""

@log_get_token("CertificateCredential")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ class ClientSecretCredential(ClientSecretCredentialBase):
: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 bool enable_persistent_cache: if True, the credential will store tokens in a persistent cache. Defaults to
False.
:keyword bool allow_unencrypted_cache: if True, the credential will fall back to a plaintext cache when encryption
is unavailable. Default to False. Has no effect when `enable_persistent_cache` is False.
"""

@log_get_token("ClientSecretCredential")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,6 @@ class DeviceCodeCredential(InteractiveCredential):
- ``expires_on`` (datetime.datetime) the UTC time at which the code will expire
If this argument isn't provided, the credential will print instructions to stdout.
:paramtype prompt_callback: Callable[str, str, ~datetime.datetime]
:keyword AuthenticationRecord authentication_record: :class:`AuthenticationRecord` returned by :func:`authenticate`
:keyword bool disable_automatic_authentication: if True, :func:`get_token` will raise
:class:`AuthenticationRequiredError` when user interaction is required to acquire a token. Defaults to False.
:keyword bool enable_persistent_cache: if True, the credential will store tokens in a persistent cache shared by
other user credentials. Defaults to False.
:keyword bool allow_unencrypted_cache: if True, the credential will fall back to a plaintext cache on platforms
where encryption is unavailable. Default to False. Has no effect when `enable_persistent_cache` is False.
"""

def __init__(self, client_id, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ class ManagedIdentityCredential(object):
the keyword arguments.

:keyword str client_id: a user-assigned identity's client ID. This is supported in all hosting environments.
:keyword identity_config: a mapping ``{parameter_name: value}`` specifying a user-assigned identity by its object
or resource ID, for example ``{"object_id": "..."}``. Check the documentation for your hosting environment to
learn what values it expects.
:paramtype identity_config: Mapping[str, str]
"""

def __init__(self, **kwargs):
Expand Down Expand Up @@ -80,7 +76,7 @@ def get_token(self, *scopes, **kwargs):
class _ManagedIdentityBase(object):
def __init__(self, endpoint, client_cls, config=None, client_id=None, **kwargs):
# type: (str, Type, Optional[Configuration], Optional[str], **Any) -> None
self._identity_config = kwargs.pop("identity_config", None) or {}
self._identity_config = kwargs.pop("_identity_config", None) or {}
if client_id:
if os.environ.get(EnvironmentVariables.MSI_ENDPOINT) and os.environ.get(EnvironmentVariables.MSI_SECRET):
# App Service: version 2017-09-1 accepts client ID as parameter "clientid"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ class SharedTokenCacheCredential(SharedTokenCacheBase):
defines authorities for other clouds.
:keyword str tenant_id: an Azure Active Directory tenant ID. Used to select an account when the cache contains
tokens for multiple identities.
:keyword AuthenticationRecord authentication_record: an authentication record returned by a user credential such as
:class:`DeviceCodeCredential` or :class:`InteractiveBrowserCredential`
:keyword bool allow_unencrypted_cache: if True, the credential will fall back to a plaintext cache when encryption
is unavailable. Defaults to False.
"""

@log_get_token("SharedTokenCacheCredential")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ class UsernamePasswordCredential(InteractiveCredential):
defines authorities for other clouds.
:keyword str tenant_id: tenant ID or a domain associated with a tenant. If not provided, defaults to the
'organizations' tenant, which supports only Azure Active Directory work or school accounts.
:keyword bool enable_persistent_cache: if True, the credential will store tokens in a persistent cache shared by
other user credentials. Defaults to False.
:keyword bool allow_unencrypted_cache: if True, the credential will fall back to a plaintext cache on platforms
where encryption is unavailable. Default to False. Has no effect when `enable_persistent_cache` is False.
"""

def __init__(self, client_id, username, password, **kwargs):
Expand All @@ -46,7 +42,7 @@ def __init__(self, client_id, username, password, **kwargs):
# first time it's asked for a token. However, we want to ensure this first authentication is not silent, to
# validate the given password. This class therefore doesn't document the authentication_record argument, and we
# discard it here.
kwargs.pop("authentication_record", None)
kwargs.pop("_authentication_record", None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to honor "_authentication_record". why not just remove this line so we ignore "authentication_record"?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like leaving the reading from kwargs. It lowers the code churn and makes it less error prone to reintroduce support for these kwargs

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. We can comment this line if pylint is not angry.
  2. We can keep this line, it does not hurt.
  3. The only possible side effect to rename it is if user uses "_authentication_record", they will get broken when we re-enable the feature. - not too bad, but not good.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Commenting the line breaks tests. We can skip them but then we may not catch regressions that complicate reverting these changes.
  2. If we keep this and similar lines, code written against 1.4.0b7 will continue to work in 1.4.0 despite using unsupported features.
  3. "_authentication_record" is underscored and undocumented: clearly not part of the public API

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am confused.

If user passes in "authentication_record", do we want it break or not?

#1 will break it while #2 will not.

Seems to me you like neither of them. :)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry to have made confusion. I was responding to each of your points, not laying out a plan.

If user passes in "authentication_record", do we want it break or not?

We want to release 1.4.0 without the application authentication and cache configuration APIs present in 1.4.0b7. Not breaking code using these APIs is tantamount to including them in the stable release. So, we want it to break.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification.

So I think just commenting this line will be good enough, right?

The only difference for adding "kwargs.pop("_authentication_record", None)" is if user passes "_authentication_record" (which is not a supported scenario), it will work in this release but will be broken when we bring the feature back. I don't think it is our intension to make this happen.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think just commenting this line will be good enough, right?

Good enough for breaking the code we want to break but at the cost of breaking our tests. Skipping those would introduce a risk of unintentionally breaking features we want in our next beta. Also, the specific case you commented on here is a simple one because the argument is discarded. In other cases commenting a single line isn't enough because the argument is used.

The only difference for adding "kwargs.pop("_authentication_record", None)" is if user passes "_authentication_record" (which is not a supported scenario), it will work in this release but will be broken when we bring the feature back. I don't think it is our intension to make this happen.

We don't support unsupported features.

super(UsernamePasswordCredential, self).__init__(client_id=client_id, **kwargs)
self._username = username
self._password = password
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ def __init__(self, tenant_id, client_id, certificate_path, **kwargs):

self._certificate = AadClientCertificate(pem_bytes, password=password)

enable_persistent_cache = kwargs.pop("enable_persistent_cache", False)
enable_persistent_cache = kwargs.pop("_enable_persistent_cache", False)
if enable_persistent_cache:
allow_unencrypted = kwargs.pop("allow_unencrypted_cache", False)
allow_unencrypted = kwargs.pop("_allow_unencrypted_cache", False)
cache = load_service_principal_cache(allow_unencrypted)
else:
cache = TokenCache()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ def __init__(self, tenant_id, client_id, client_secret, **kwargs):
"tenant_id should be an Azure Active Directory tenant's id (also called its 'directory id')"
)

enable_persistent_cache = kwargs.pop("enable_persistent_cache", False)
enable_persistent_cache = kwargs.pop("_enable_persistent_cache", False)
if enable_persistent_cache:
allow_unencrypted = kwargs.pop("allow_unencrypted_cache", False)
allow_unencrypted = kwargs.pop("_allow_unencrypted_cache", False)
cache = load_service_principal_cache(allow_unencrypted)
else:
cache = TokenCache()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ def _build_auth_record(response):

class InteractiveCredential(MsalCredential):
def __init__(self, **kwargs):
self._disable_automatic_authentication = kwargs.pop("disable_automatic_authentication", False)
self._auth_record = kwargs.pop("authentication_record", None) # type: Optional[AuthenticationRecord]
self._disable_automatic_authentication = kwargs.pop("_disable_automatic_authentication", False)
self._auth_record = kwargs.pop("_authentication_record", None) # type: Optional[AuthenticationRecord]
if self._auth_record:
kwargs.pop("client_id", None) # authentication_record overrides client_id argument
tenant_id = kwargs.pop("tenant_id", None) or self._auth_record.tenant_id
Expand All @@ -97,8 +97,6 @@ def get_token(self, *scopes, **kwargs):
required data, state, or platform support
:raises ~azure.core.exceptions.ClientAuthenticationError: authentication failed. The error's ``message``
attribute gives a reason.
:raises AuthenticationRequiredError: user interaction is necessary to acquire a token, and the credential is
configured not to begin this automatically. Call :func:`authenticate` to begin interactive authentication.
"""
if not scopes:
message = "'get_token' requires at least one scope"
Expand Down Expand Up @@ -140,7 +138,7 @@ def get_token(self, *scopes, **kwargs):
_LOGGER.info("%s.get_token succeeded", self.__class__.__name__)
return AccessToken(result["access_token"], now + int(result["expires_in"]))

def authenticate(self, **kwargs):
def _authenticate(self, **kwargs):
# type: (**Any) -> AuthenticationRecord
"""Interactively authenticate a user.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ def __init__(self, client_id, client_credential=None, **kwargs):

self._cache = kwargs.pop("_cache", None) # internal, for use in tests
if not self._cache:
if kwargs.pop("enable_persistent_cache", False):
allow_unencrypted = kwargs.pop("allow_unencrypted_cache", False)
if kwargs.pop("_enable_persistent_cache", False):
allow_unencrypted = kwargs.pop("_allow_unencrypted_cache", False)
self._cache = load_user_cache(allow_unencrypted)
else:
self._cache = msal.TokenCache()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
# pylint:disable=unused-import,ungrouped-imports
from typing import Any, Iterable, List, Mapping, Optional
from .._internal import AadClientBase
from azure.identity import AuthenticationRecord
from azure.identity._auth_record import AuthenticationRecord

CacheItem = Mapping[str, str]

Expand Down Expand Up @@ -90,7 +90,7 @@ class SharedTokenCacheBase(ABC):
def __init__(self, username=None, **kwargs): # pylint:disable=unused-argument
# type: (Optional[str], **Any) -> None

self._auth_record = kwargs.pop("authentication_record", None) # type: Optional[AuthenticationRecord]
self._auth_record = kwargs.pop("_authentication_record", None) # type: Optional[AuthenticationRecord]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I would like to use

# self._auth_record = kwargs.pop("authentication_record", None)
self._auth_record = None

But I will let you to decide it.

if self._auth_record:
# authenticate in the tenant that produced the record unless 'tenant_id' specifies another
authenticating_tenant = kwargs.pop("tenant_id", None) or self._auth_record.tenant_id
Expand Down Expand Up @@ -118,7 +118,7 @@ def _initialize(self):
return

if not self._cache and self.supported():
allow_unencrypted = self._client_kwargs.get("allow_unencrypted_cache", False)
allow_unencrypted = self._client_kwargs.get("_allow_unencrypted_cache", True)
try:
self._cache = load_user_cache(allow_unencrypted)
except Exception: # pylint:disable=broad-except
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ class ClientSecretCredential(AsyncCredentialBase, ClientSecretCredentialBase):
: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 bool enable_persistent_cache: if True, the credential will store tokens in a persistent cache. Defaults to
False.
:keyword bool allow_unencrypted_cache: if True, the credential will fall back to a plaintext cache when encryption
is unavailable. Default to False. Has no effect when `enable_persistent_cache` is False.
"""

async def __aenter__(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ class ManagedIdentityCredential(AsyncCredentialBase):
the keyword arguments.

:keyword str client_id: a user-assigned identity's client ID. This is supported in all hosting environments.
:keyword identity_config: a mapping ``{parameter_name: value}`` specifying a user-assigned identity by its object
or resource ID, for example ``{"object_id": "..."}``. Check the documentation for your hosting environment to
learn what values it expects.
:paramtype identity_config: Mapping[str, str]
"""

def __init__(self, **kwargs: "Any") -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ class SharedTokenCacheCredential(SharedTokenCacheBase, AsyncCredentialBase):
defines authorities for other clouds.
:keyword str tenant_id: an Azure Active Directory tenant ID. Used to select an account when the cache contains
tokens for multiple identities.
:keyword AuthenticationRecord authentication_record: an authentication record returned by a user credential such as
:class:`DeviceCodeCredential` or :class:`InteractiveBrowserCredential`
:keyword bool allow_unencrypted_cache: if True, the credential will fall back to a plaintext cache when encryption
is unavailable. Defaults to False.
"""

async def __aenter__(self):
Expand Down
37 changes: 0 additions & 37 deletions sdk/identity/azure-identity/samples/README.md

This file was deleted.

38 changes: 0 additions & 38 deletions sdk/identity/azure-identity/samples/control_interactive_prompts.py

This file was deleted.

Loading