From 63ee04203532b26cbad84c764fcfb9a4b5c8fd4b Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Fri, 2 Aug 2019 12:52:47 -0700 Subject: [PATCH 01/11] fix mypy errors --- .../azure-identity/azure/identity/_authn_client.py | 14 ++++++++++---- .../azure/identity/aio/credentials.py | 6 +++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/sdk/identity/azure-identity/azure/identity/_authn_client.py b/sdk/identity/azure-identity/azure/identity/_authn_client.py index 65f61f090ccd..95ded9b38177 100644 --- a/sdk/identity/azure-identity/azure/identity/_authn_client.py +++ b/sdk/identity/azure-identity/azure/identity/_authn_client.py @@ -19,8 +19,9 @@ except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: + # pylint:disable=unused-import from time import struct_time - from typing import Any, Dict, Iterable, Mapping, Optional + from typing import Any, Dict, Iterable, Mapping, Optional, Union from azure.core.pipeline import PipelineResponse from azure.core.pipeline.policies import HTTPPolicy @@ -60,13 +61,13 @@ def _deserialize_and_cache_token(self, response, scopes, request_time): token = payload["access_token"] # AccessToken wants expires_on as an int - expires_on = payload.get("expires_on") or int(payload["expires_in"]) + request_time + expires_on = payload.get("expires_on") or int(payload["expires_in"]) + request_time # type: Union[str, int] try: expires_on = int(expires_on) except ValueError: # probably an App Service MSI response, convert it to epoch seconds try: - t = self._parse_app_service_expires_on(expires_on) + t = self._parse_app_service_expires_on(expires_on) # type: ignore expires_on = calendar.timegm(t) except ValueError: # have a token but don't know when it expires -> treat it as single-use @@ -120,7 +121,12 @@ class AuthnClient(AuthnClientBase): def __init__(self, auth_url, config=None, policies=None, transport=None, **kwargs): # type: (str, Optional[Configuration], Optional[Iterable[HTTPPolicy]], Optional[HttpTransport], Mapping[str, Any]) -> None config = config or self._create_config(**kwargs) - policies = policies or [ContentDecodePolicy(), config.retry_policy, config.logging_policy, DistributedTracingPolicy()] + policies = policies or [ + ContentDecodePolicy(), + config.retry_policy, + config.logging_policy, + DistributedTracingPolicy(), + ] if not transport: transport = RequestsTransport(**kwargs) self._pipeline = Pipeline(transport=transport, policies=policies) diff --git a/sdk/identity/azure-identity/azure/identity/aio/credentials.py b/sdk/identity/azure-identity/azure/identity/aio/credentials.py index fd80e2bc1051..794db6dbb53e 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/credentials.py +++ b/sdk/identity/azure-identity/azure/identity/aio/credentials.py @@ -17,7 +17,7 @@ from ._managed_identity import ImdsCredential, MsiCredential from .._base import ClientSecretCredentialBase, CertificateCredentialBase from ..constants import Endpoints, EnvironmentVariables -from ..credentials import ChainedTokenCredential +from ..credentials import ChainedTokenCredential as SyncChainedTokenCredential # pylint:disable=too-few-public-methods @@ -156,7 +156,7 @@ async def get_token(self, *scopes: str) -> AccessToken: return AccessToken() -class ChainedTokenCredential(ChainedTokenCredential): +class ChainedTokenCredential(SyncChainedTokenCredential): """ A sequence of credentials that is itself a credential. Its ``get_token`` method calls ``get_token`` on each credential in the sequence, in order, returning the first valid token received. @@ -165,7 +165,7 @@ class ChainedTokenCredential(ChainedTokenCredential): :type credentials: :class:`azure.core.credentials.TokenCredential` """ - async def get_token(self, *scopes: str) -> AccessToken: # type: ignore + async def get_token(self, *scopes: str) -> AccessToken: """ Asynchronously request a token from each credential, in order, returning the first token received. If none provides a token, raises :class:`azure.core.exceptions.ClientAuthenticationError` From ec6dcee293a8dbff6d3686a47fbf497d811665ef Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Fri, 2 Aug 2019 12:54:52 -0700 Subject: [PATCH 02/11] update version --- .../azure-identity/azure/identity/{version.py => _version.py} | 2 +- sdk/identity/azure-identity/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename sdk/identity/azure-identity/azure/identity/{version.py => _version.py} (88%) diff --git a/sdk/identity/azure-identity/azure/identity/version.py b/sdk/identity/azure-identity/azure/identity/_version.py similarity index 88% rename from sdk/identity/azure-identity/azure/identity/version.py rename to sdk/identity/azure-identity/azure/identity/_version.py index a4040f093c86..946e62e8cf55 100644 --- a/sdk/identity/azure-identity/azure/identity/version.py +++ b/sdk/identity/azure-identity/azure/identity/_version.py @@ -2,4 +2,4 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -VERSION = "1.0.0b1" +VERSION = "1.0.0b2" diff --git a/sdk/identity/azure-identity/setup.py b/sdk/identity/azure-identity/setup.py index 783ef669f72a..22fedd9d5810 100644 --- a/sdk/identity/azure-identity/setup.py +++ b/sdk/identity/azure-identity/setup.py @@ -30,7 +30,7 @@ except ImportError: pass -with open(os.path.join(package_folder_path, "version.py"), "r") as fd: +with open(os.path.join(package_folder_path, "_version.py"), "r") as fd: VERSION = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE).group(1) if not VERSION: raise RuntimeError("Cannot find version information") From 26cfa164ce86f04bc63b9f934e09f0ed3a145f2b Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Fri, 2 Aug 2019 14:22:59 -0700 Subject: [PATCH 03/11] _ modules to clean up docs, fix some docstrings --- .../azure-identity/azure/identity/__init__.py | 6 +-- .../azure-identity/azure/identity/_base.py | 2 +- .../{browser_auth.py => _browser_auth.py} | 10 ++--- .../identity/{constants.py => _constants.py} | 0 .../azure/identity/_managed_identity.py | 2 +- .../azure/identity/aio/__init__.py | 4 +- .../azure/identity/aio/_managed_identity.py | 2 +- .../azure/identity/aio/credentials.py | 24 ++++++----- .../azure/identity/credentials.py | 40 +++++++++---------- sdk/identity/azure-identity/conftest.py | 2 +- .../azure-identity/tests/test_identity.py | 8 ++-- .../tests/test_identity_async.py | 2 +- .../azure-identity/tests/test_live_async.py | 1 - .../tests/test_managed_identity.py | 2 +- .../tests/test_managed_identity_async.py | 2 +- 15 files changed, 56 insertions(+), 51 deletions(-) rename sdk/identity/azure-identity/azure/identity/{browser_auth.py => _browser_auth.py} (92%) rename sdk/identity/azure-identity/azure/identity/{constants.py => _constants.py} (100%) diff --git a/sdk/identity/azure-identity/azure/identity/__init__.py b/sdk/identity/azure-identity/azure/identity/__init__.py index 5a9ccc7aad36..73ae14193dde 100644 --- a/sdk/identity/azure-identity/azure/identity/__init__.py +++ b/sdk/identity/azure-identity/azure/identity/__init__.py @@ -2,7 +2,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -from .browser_auth import InteractiveBrowserCredential +from ._browser_auth import InteractiveBrowserCredential from .credentials import ( CertificateCredential, ChainedTokenCredential, @@ -19,10 +19,10 @@ class DefaultAzureCredential(ChainedTokenCredential): A default credential capable of handling most Azure SDK authentication scenarios. When environment variable configuration is present, it authenticates as a service principal - using :class:`identity.EnvironmentCredential`. + using :class:`azure.identity.EnvironmentCredential`. When environment configuration is not present, it authenticates with a managed identity - using :class:`identity.ManagedIdentityCredential`. + using :class:`azure.identity.ManagedIdentityCredential`. """ def __init__(self, **kwargs): diff --git a/sdk/identity/azure-identity/azure/identity/_base.py b/sdk/identity/azure-identity/azure/identity/_base.py index 5938ce608288..d239f308abca 100644 --- a/sdk/identity/azure-identity/azure/identity/_base.py +++ b/sdk/identity/azure-identity/azure/identity/_base.py @@ -9,7 +9,7 @@ from cryptography.hazmat.backends import default_backend from msal.oauth2cli import JwtSigner -from .constants import Endpoints +from ._constants import Endpoints try: from typing import TYPE_CHECKING diff --git a/sdk/identity/azure-identity/azure/identity/browser_auth.py b/sdk/identity/azure-identity/azure/identity/_browser_auth.py similarity index 92% rename from sdk/identity/azure-identity/azure/identity/browser_auth.py rename to sdk/identity/azure-identity/azure/identity/_browser_auth.py index 921d70e635f2..aaf4451f630e 100644 --- a/sdk/identity/azure-identity/azure/identity/browser_auth.py +++ b/sdk/identity/azure-identity/azure/identity/_browser_auth.py @@ -30,13 +30,13 @@ class InteractiveBrowserCredential(ConfidentialClientCredential): https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-oauth-code :param str client_id: the application's client ID - :param str secret: one of the application's client secrets + :param str client_secret: one of the application's client secrets - **Keyword arguments:** + Keyword arguments + - *tenant (str)*: a tenant ID or a domain associated with a tenant. Defaults to the 'organizations' tenant, + which can authenticate work or school accounts. + - *timeout (int)*: seconds to wait for the user to complete authentication. Defaults to 300 (5 minutes). - *tenant (str)* - a tenant ID or a domain associated with a tenant. If not provided, the credential defaults to the - 'organizations' tenant, which can authenticate work or school accounts. - *timeout (str)* - seconds to wait for the user to complete authentication. Defaults to 300 (5 minutes). """ def __init__(self, client_id, client_secret, **kwargs): diff --git a/sdk/identity/azure-identity/azure/identity/constants.py b/sdk/identity/azure-identity/azure/identity/_constants.py similarity index 100% rename from sdk/identity/azure-identity/azure/identity/constants.py rename to sdk/identity/azure-identity/azure/identity/_constants.py diff --git a/sdk/identity/azure-identity/azure/identity/_managed_identity.py b/sdk/identity/azure-identity/azure/identity/_managed_identity.py index 9c3c0cd7d982..97946fd38e0c 100644 --- a/sdk/identity/azure-identity/azure/identity/_managed_identity.py +++ b/sdk/identity/azure-identity/azure/identity/_managed_identity.py @@ -19,7 +19,7 @@ from azure.core.pipeline.policies import ContentDecodePolicy, HeadersPolicy, NetworkTraceLoggingPolicy, RetryPolicy from ._authn_client import AuthnClient -from .constants import Endpoints, EnvironmentVariables +from ._constants import Endpoints, EnvironmentVariables class _ManagedIdentityBase(object): diff --git a/sdk/identity/azure-identity/azure/identity/aio/__init__.py b/sdk/identity/azure-identity/azure/identity/aio/__init__.py index a720d5e285bd..7610e4d26df3 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/__init__.py +++ b/sdk/identity/azure-identity/azure/identity/aio/__init__.py @@ -16,10 +16,10 @@ class DefaultAzureCredential(ChainedTokenCredential): A default credential capable of handling most Azure SDK authentication scenarios. When environment variable configuration is present, it authenticates as a service principal - using :class:`identity.aio.EnvironmentCredential`. + using :class:`azure.identity.aio.EnvironmentCredential`. When environment configuration is not present, it authenticates with a managed identity - using :class:`identity.aio.ManagedIdentityCredential`. + using :class:`azure.identity.aio.ManagedIdentityCredential`. """ def __init__(self, **kwargs): diff --git a/sdk/identity/azure-identity/azure/identity/aio/_managed_identity.py b/sdk/identity/azure-identity/azure/identity/aio/_managed_identity.py index 9d8eeb46a67c..84d7e7409c32 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_managed_identity.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_managed_identity.py @@ -11,7 +11,7 @@ from azure.core.pipeline.policies import ContentDecodePolicy, HeadersPolicy, NetworkTraceLoggingPolicy, AsyncRetryPolicy from ._authn_client import AsyncAuthnClient -from ..constants import Endpoints, EnvironmentVariables +from .._constants import Endpoints, EnvironmentVariables from .._managed_identity import _ManagedIdentityBase diff --git a/sdk/identity/azure-identity/azure/identity/aio/credentials.py b/sdk/identity/azure-identity/azure/identity/aio/credentials.py index 794db6dbb53e..4d8011c65016 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/credentials.py +++ b/sdk/identity/azure-identity/azure/identity/aio/credentials.py @@ -16,7 +16,7 @@ from ._authn_client import AsyncAuthnClient from ._managed_identity import ImdsCredential, MsiCredential from .._base import ClientSecretCredentialBase, CertificateCredentialBase -from ..constants import Endpoints, EnvironmentVariables +from .._constants import Endpoints, EnvironmentVariables from ..credentials import ChainedTokenCredential as SyncChainedTokenCredential # pylint:disable=too-few-public-methods @@ -80,18 +80,24 @@ async def get_token(self, *scopes: str) -> AccessToken: class EnvironmentCredential: """ - Authenticates as a service principal using a client ID/secret pair or a certificate, - depending on environment variable settings. - - These environment variables are required: + Authenticates as a service principal using a client secret or a certificate, or as a user with a username and + password, depending on environment variable settings. Configuration is attempted in this order, using these + environment variables: + Service principal with secret: - **AZURE_CLIENT_ID**: the service principal's client ID + - **AZURE_CLIENT_SECRET**: one of the service principal's client secrets - **AZURE_TENANT_ID**: ID of the service principal's tenant. Also called its 'directory' ID. - Additionally, set **one** of these to configure client secret or certificate authentication: - - - **AZURE_CLIENT_SECRET**: one of the service principal's client secrets + Service principal with certificate: + - **AZURE_CLIENT_ID**: the service principal's client ID - **AZURE_CLIENT_CERTIFICATE_PATH**: path to a PEM-encoded certificate file including the private key + - **AZURE_TENANT_ID**: ID of the service principal's tenant. Also called its 'directory' ID. + + User with username and password: + - **AZURE_CLIENT_ID**: the application's client ID + - **AZURE_USERNAME**: a username (usually an email address) + - **AZURE_PASSWORD**: that user's password """ def __init__(self, **kwargs: Mapping[str, Any]) -> None: @@ -175,7 +181,7 @@ async def get_token(self, *scopes: str) -> AccessToken: :raises: :class:`azure.core.exceptions.ClientAuthenticationError` """ history = [] - for credential in self._credentials: + for credential in self.credentials: try: return await credential.get_token(*scopes) except ClientAuthenticationError as ex: diff --git a/sdk/identity/azure-identity/azure/identity/credentials.py b/sdk/identity/azure-identity/azure/identity/credentials.py index 2465198c53ac..6e107ac63f1e 100644 --- a/sdk/identity/azure-identity/azure/identity/credentials.py +++ b/sdk/identity/azure-identity/azure/identity/credentials.py @@ -14,10 +14,11 @@ from azure.core.pipeline.policies import ContentDecodePolicy, HeadersPolicy, NetworkTraceLoggingPolicy, RetryPolicy from ._authn_client import AuthnClient +from ._browser_auth import InteractiveBrowserCredential from ._base import ClientSecretCredentialBase, CertificateCredentialBase from ._internal import PublicClientCredential, wrap_exceptions from ._managed_identity import ImdsCredential, MsiCredential -from .constants import Endpoints, EnvironmentVariables +from ._constants import Endpoints, EnvironmentVariables try: from typing import TYPE_CHECKING @@ -200,7 +201,7 @@ def __init__(self, *credentials): # type: (*TokenCredential) -> None if not credentials: raise ValueError("at least one credential is required") - self._credentials = credentials + self.credentials = credentials def get_token(self, *scopes): # type (*str) -> AccessToken @@ -213,7 +214,7 @@ def get_token(self, *scopes): :raises: :class:`azure.core.exceptions.ClientAuthenticationError` """ history = [] - for credential in self._credentials: + for credential in self.credentials: try: return credential.get_token(*scopes) except ClientAuthenticationError as ex: @@ -238,7 +239,8 @@ class DeviceCodeCredential(PublicClientCredential): """ Authenticates users through the device code flow. When ``get_token`` is called, this credential acquires a verification URL and code from Azure Active Directory. A user must browse to the URL, enter the code, and - authenticate with Directory. If the user authenticates successfully, the credential receives an access token. + authenticate with Azure Active Directory. If the user authenticates successfully, the credential receives + an access token. This credential doesn't cache tokens--each ``get_token`` call begins a new authentication flow. @@ -246,20 +248,19 @@ class DeviceCodeCredential(PublicClientCredential): https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code :param str client_id: the application's ID - :param prompt_callback: (optional) A callback enabling control of how authentication instructions are presented. + :param prompt_callback: + (optional) A callback enabling control of how authentication instructions are presented. + Must accept arguments (``verification_uri``, ``user_code``, ``expires_in``): + - ``verification_uri`` (str) the URL the user must visit + - ``user_code`` (str) the code the user must enter there + - ``expires_in`` (int) the number of seconds the code will be valid If not provided, the credential will print instructions to stdout. - :type prompt_callback: A callable accepting arguments (``verification_uri``, ``user_code``, ``expires_in``): - - ``verification_uri`` (str) the URL the user must visit - - ``user_code`` (str) the code the user must enter there - - ``expires_in`` (int) the number of seconds the code will be valid - **Keyword arguments:** - - - *tenant (str)* - tenant ID or a domain associated with a tenant. If not provided, the credential defaults to the - 'organizations' tenant, which supports only Azure Active Directory work or school accounts. - - - *timeout (int)* - seconds to wait for the user to authenticate. Defaults to the validity period of the device code - as set by Azure Active Directory, which also prevails when ``timeout`` is longer. + Keyword arguments + - *tenant (str)* - 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. + - *timeout (int)* - seconds to wait for the user to authenticate. Defaults to the validity period of the device + code as set by Azure Active Directory, which also prevails when ``timeout`` is longer. """ @@ -330,10 +331,9 @@ class UsernamePasswordCredential(PublicClientCredential): :param str username: the user's username (usually an email address) :param str password: the user's password - **Keyword arguments:** - - - **tenant (str)** - a tenant ID or a domain associated with a tenant. If not provided, defaults to the - 'organizations' tenant. + Keyword arguments + - *tenant (str)* - 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. """ diff --git a/sdk/identity/azure-identity/conftest.py b/sdk/identity/azure-identity/conftest.py index 6bdfa4d3ddee..d2e94c1e9cbd 100644 --- a/sdk/identity/azure-identity/conftest.py +++ b/sdk/identity/azure-identity/conftest.py @@ -6,7 +6,7 @@ import sys import pytest -from azure.identity.constants import EnvironmentVariables +from azure.identity._constants import EnvironmentVariables # IMDS tests must be run explicitly collect_ignore_glob = ["*imds*"] # pylint:disable=invalid-name diff --git a/sdk/identity/azure-identity/tests/test_identity.py b/sdk/identity/azure-identity/tests/test_identity.py index 0319e6a2938a..40aa4f8df35d 100644 --- a/sdk/identity/azure-identity/tests/test_identity.py +++ b/sdk/identity/azure-identity/tests/test_identity.py @@ -26,7 +26,7 @@ UsernamePasswordCredential, ) from azure.identity._managed_identity import ImdsCredential -from azure.identity.constants import EnvironmentVariables +from azure.identity._constants import EnvironmentVariables import pytest from helpers import mock_response, Request, validating_transport @@ -299,7 +299,7 @@ def test_device_code_credential_timeout(): assert "timed out" in ex.value.message.lower() -@patch("azure.identity.browser_auth.webbrowser.open", lambda _: None) # prevent the credential opening a browser +@patch("azure.identity._browser_auth.webbrowser.open", lambda _: None) # prevent the credential opening a browser def test_interactive_credential(): oauth_state = "state" expected_token = "access-token" @@ -333,12 +333,12 @@ def test_interactive_credential(): ) # ensure the request beginning the flow has a known state value - with patch("azure.identity.browser_auth.uuid.uuid4", lambda: oauth_state): + with patch("azure.identity._browser_auth.uuid.uuid4", lambda: oauth_state): token = credential.get_token("scope") assert token.token == expected_token -@patch("azure.identity.browser_auth.webbrowser.open", lambda _: None) # prevent the credential opening a browser +@patch("azure.identity._browser_auth.webbrowser.open", lambda _: None) # prevent the credential opening a browser def test_interactive_credential_timeout(): # mock transport handles MSAL's tenant discovery transport = Mock( diff --git a/sdk/identity/azure-identity/tests/test_identity_async.py b/sdk/identity/azure-identity/tests/test_identity_async.py index 70d06ed7f8c7..ce432f62473b 100644 --- a/sdk/identity/azure-identity/tests/test_identity_async.py +++ b/sdk/identity/azure-identity/tests/test_identity_async.py @@ -20,7 +20,7 @@ ManagedIdentityCredential, ) from azure.identity.aio._managed_identity import ImdsCredential -from azure.identity.constants import EnvironmentVariables +from azure.identity._constants import EnvironmentVariables from helpers import mock_response, Request, async_validating_transport diff --git a/sdk/identity/azure-identity/tests/test_live_async.py b/sdk/identity/azure-identity/tests/test_live_async.py index c64279258e97..49a16a328e4f 100644 --- a/sdk/identity/azure-identity/tests/test_live_async.py +++ b/sdk/identity/azure-identity/tests/test_live_async.py @@ -10,7 +10,6 @@ import mock # type: ignore from azure.identity.aio import DefaultAzureCredential, CertificateCredential, ClientSecretCredential -from azure.identity.constants import EnvironmentVariables import pytest ARM_SCOPE = "https://management.azure.com/.default" diff --git a/sdk/identity/azure-identity/tests/test_managed_identity.py b/sdk/identity/azure-identity/tests/test_managed_identity.py index 0840c1f9d4c4..2129da897083 100644 --- a/sdk/identity/azure-identity/tests/test_managed_identity.py +++ b/sdk/identity/azure-identity/tests/test_managed_identity.py @@ -11,7 +11,7 @@ from azure.core.credentials import AccessToken from azure.identity import ManagedIdentityCredential -from azure.identity.constants import Endpoints, EnvironmentVariables +from azure.identity._constants import Endpoints, EnvironmentVariables from helpers import validating_transport, mock_response, Request diff --git a/sdk/identity/azure-identity/tests/test_managed_identity_async.py b/sdk/identity/azure-identity/tests/test_managed_identity_async.py index ee4fd0fdadcc..6f07d0d38d5f 100644 --- a/sdk/identity/azure-identity/tests/test_managed_identity_async.py +++ b/sdk/identity/azure-identity/tests/test_managed_identity_async.py @@ -7,7 +7,7 @@ from azure.core.credentials import AccessToken from azure.identity.aio import ManagedIdentityCredential -from azure.identity.constants import Endpoints, EnvironmentVariables +from azure.identity._constants import Endpoints, EnvironmentVariables import pytest from helpers import async_validating_transport, mock_response, Request From 3e25b6d89f0a5459e910a26fc958c49478162890 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Fri, 2 Aug 2019 15:15:28 -0700 Subject: [PATCH 04/11] update README --- sdk/identity/azure-identity/README.md | 59 ++++++++++++++++++--------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/sdk/identity/azure-identity/README.md b/sdk/identity/azure-identity/README.md index 22b1bf6c2019..5df7ef702a6c 100644 --- a/sdk/identity/azure-identity/README.md +++ b/sdk/identity/azure-identity/README.md @@ -5,6 +5,7 @@ It supports token authentication using an Azure Active Directory This library is in preview and currently supports: - [Service principal authentication](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals) - [Managed identity authentication](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) + - User authentication [Source code](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/identity/azure-identity/azure/identity) | [Package (PyPI)](https://pypi.org/project/azure-identity/) @@ -61,18 +62,22 @@ configuration: |credential class|identity|configuration |-|-|- -|`DefaultAzureCredential`|service principal or managed identity|none for managed identity; [environment variables](#environment-variables) for service principal +|`DefaultAzureCredential`|service principal, managed identity or user|none for managed identity; [environment variables](#environment-variables) for service principal or user authentication |`ManagedIdentityCredential`|managed identity|none |`EnvironmentCredential`|service principal|[environment variables](#environment-variables) |`ClientSecretCredential`|service principal|constructor parameters |`CertificateCredential`|service principal|constructor parameters +|[`DeviceCodeCredential`](https://azure.github.io/azure-sdk-for-python/ref/azure.identity.html#azure.identity.credentials.DeviceCodeCredential)|user|constructor parameters +|[`InteractiveBrowserCredential`](https://azure.github.io/azure-sdk-for-python/ref/azure.identity.html#azure.identity.InteractiveBrowserCredential)|user|constructor parameters +|[`UsernamePasswordCredential`](https://azure.github.io/azure-sdk-for-python/ref/azure.identity.html#azure.identity.credentials.UsernamePasswordCredential)|user|constructor parameters Credentials can be chained together and tried in turn until one succeeds; see [chaining credentials](#chaining-credentials) for details. -All credentials have an async equivalent in the `azure.identity.aio` namespace. -These are supported on Python 3.5.3+. See the -[async credentials](#async-credentials) example for details. +Service principal and managed identity credentials have an async equivalent in +the `azure.identity.aio` namespace, supported on Python 3.5.3+. See the +[async credentials](#async-credentials) example for details. Async user +credentials will be part of a future release. ## DefaultAzureCredential `DefaultAzureCredential` is appropriate for most applications intended to run @@ -90,18 +95,34 @@ for more information. ## Environment variables -`DefaultAzureCredential` and `EnvironmentCredential` are configured for service -principal authentication with these environment variables: - -|variable name|value -|-|- -|`AZURE_CLIENT_ID`|service principal's app id -|`AZURE_TENANT_ID`|id of the principal's Azure Active Directory tenant -|`AZURE_CLIENT_SECRET`|one of the service principal's client secrets -|`AZURE_CLIENT_CERTIFICATE_PATH`|path to a PEM-encoded certificate file including private key (without password) - -Either `AZURE_CLIENT_SECRET` or `AZURE_CLIENT_CERTIFICATE_PATH` must be set. -If both are set, the client secret will be used. +`DefaultAzureCredential` and `EnvironmentCredential` can be configured with +environment variables. Each type of authentication requires values for specific +variables: + +#### Service principal with secret +>|variable name|value +>|-|- +>|`AZURE_CLIENT_ID`|service principal's app id +>|`AZURE_TENANT_ID`|id of the principal's Azure Active Directory tenant +>|`AZURE_CLIENT_SECRET`|one of the service principal's client secrets + +#### Service principal with certificate +>|variable name|value +>|-|- +>|`AZURE_CLIENT_ID`|service principal's app id +>|`AZURE_TENANT_ID`|id of the principal's Azure Active Directory tenant +>|`AZURE_CLIENT_CERTIFICATE_PATH`|path to a PEM-encoded certificate file including private key (without password) + +#### Username and password +>|variable name|value +>|-|- +>|`AZURE_CLIENT_ID`|id of an Azure Active Directory application +>|`AZURE_USERNAME`|a username (usually an email address) +>|`AZURE_PASSWORD`|that user's password + +Configuration is attempted in the above order. For example, if both +`AZURE_CLIENT_SECRET` and `AZURE_CLIENT_CERTIFICATE_PATH` have values, +`AZURE_CLIENT_SECRET` will be used. # Examples ## Authenticating with `DefaultAzureCredential` @@ -173,9 +194,9 @@ client = EventHubClient(host, event_hub_path, credential) ``` ## Async credentials: -This library includes a complete async API supported on Python 3.5+. To use the -async credentials in `azure.identity.aio`, you must first install an async -transport, such as [`aiohttp`](https://pypi.org/project/aiohttp/). See +This library includes an async API supported on Python 3.5+. To use the async +credentials in `azure.identity.aio`, you must first install an async transport, +such as [`aiohttp`](https://pypi.org/project/aiohttp/). See [azure-core documentation](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/core/azure-core/README.md#transport) for more information. From 86263556752ea84439816143d26d5c92a59001e5 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 5 Aug 2019 09:30:08 -0700 Subject: [PATCH 05/11] update azure-core dependency --- sdk/identity/azure-identity/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/setup.py b/sdk/identity/azure-identity/setup.py index 22fedd9d5810..c20e47ee9152 100644 --- a/sdk/identity/azure-identity/setup.py +++ b/sdk/identity/azure-identity/setup.py @@ -69,6 +69,6 @@ "azure", ] ), - install_requires=["azure-core<2.0.0,>=1.0.0b1", "cryptography>=2.1.4", "msal~=0.4.1", "six>=1.6"], + install_requires=["azure-core<2.0.0,>=1.0.0b2", "cryptography>=2.1.4", "msal~=0.4.1", "six>=1.6"], extras_require={":python_version<'3.0'": ["azure-nspkg"], ":python_version<'3.5'": ["typing"]}, ) From 1047b191115687e885b395eb85716d030637efd9 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 5 Aug 2019 09:34:05 -0700 Subject: [PATCH 06/11] update history --- sdk/identity/azure-identity/HISTORY.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sdk/identity/azure-identity/HISTORY.md b/sdk/identity/azure-identity/HISTORY.md index 13f091b5a392..b36ac8d216f3 100644 --- a/sdk/identity/azure-identity/HISTORY.md +++ b/sdk/identity/azure-identity/HISTORY.md @@ -1,5 +1,20 @@ # Release History +## 1.0.0b2 +Breaking changes: +- Removed `Configuration` from the public API in prepration for entirely +kwargs-based configuration. Static `create_config` methods have been renamed +`_create_config`, and will be removed entirely in a future release. +- This version of the library requires [`azure-core`](https://pypi.org/project/azure-core/) +1.0.0b2 and [MSAL](https://pypi.org/project/msal/) 0.4.1 + +New credentials: +- Added credentials for authenticating users: +[`DeviceCodeCredential`](https://azure.github.io/azure-sdk-for-python/ref/azure.identity.html#azure.identity.DeviceCodeCredential), +[`InteractiveBrowserCredential`](https://azure.github.io/azure-sdk-for-python/ref/azure.identity.html#azure.identity.InteractiveBrowserCredential), +[`UsernamePasswordCredential`](https://azure.github.io/azure-sdk-for-python/ref/azure.identity.html#azure.identity.UsernamePasswordCredential) + - async versions of these credentials will be added in a future release + ## 1.0.0b1 (2019-06-28) Version 1.0.0b1 is the first preview of our efforts to create a user-friendly and Pythonic authentication API for Azure SDK client libraries. For more From fbc3d9ecf0f44cbb0dedb8e37c8a6ff818d113ab Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 5 Aug 2019 10:12:39 -0700 Subject: [PATCH 07/11] mock is required for Python < 3.3 --- sdk/identity/azure-identity/HISTORY.md | 7 +++++-- sdk/identity/azure-identity/setup.py | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/sdk/identity/azure-identity/HISTORY.md b/sdk/identity/azure-identity/HISTORY.md index b36ac8d216f3..9978d05140fe 100644 --- a/sdk/identity/azure-identity/HISTORY.md +++ b/sdk/identity/azure-identity/HISTORY.md @@ -5,8 +5,11 @@ Breaking changes: - Removed `Configuration` from the public API in prepration for entirely kwargs-based configuration. Static `create_config` methods have been renamed `_create_config`, and will be removed entirely in a future release. -- This version of the library requires [`azure-core`](https://pypi.org/project/azure-core/) -1.0.0b2 and [MSAL](https://pypi.org/project/msal/) 0.4.1 + +Dependency changes: +- Updated [`azure-core`](https://pypi.org/project/azure-core/) to 1.0.0b2 +- Updated [MSAL](https://pypi.org/project/msal/) 0.4.1 +- New dependency for Python 2.7: [mock](https://pypi.org/project/mock/) New credentials: - Added credentials for authenticating users: diff --git a/sdk/identity/azure-identity/setup.py b/sdk/identity/azure-identity/setup.py index c20e47ee9152..aeb53fceeda4 100644 --- a/sdk/identity/azure-identity/setup.py +++ b/sdk/identity/azure-identity/setup.py @@ -70,5 +70,9 @@ ] ), install_requires=["azure-core<2.0.0,>=1.0.0b2", "cryptography>=2.1.4", "msal~=0.4.1", "six>=1.6"], - extras_require={":python_version<'3.0'": ["azure-nspkg"], ":python_version<'3.5'": ["typing"]}, + extras_require={ + ":python_version<'3.0'": ["azure-nspkg"], + ":python_version<'3.3'": ["mock"], + ":python_version<'3.5'": ["typing"], + }, ) From a1c1d83ffe8ea4926f82888377ef5ab96a3cec21 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 5 Aug 2019 10:47:10 -0700 Subject: [PATCH 08/11] min azure-core is 1.0.0b2 --- shared_requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared_requirements.txt b/shared_requirements.txt index e6f96057b574..c03066fba99e 100644 --- a/shared_requirements.txt +++ b/shared_requirements.txt @@ -6,7 +6,7 @@ azure-cognitiveservices-language-nspkg azure-cognitiveservices-search-nspkg azure-cognitiveservices-vision-nspkg azure-common~=1.1 -azure-core<2.0.0,>=1.0.0b1 +azure-core<2.0.0,>=1.0.0b2 azure-cosmosdb-table~=1.0 azure-datalake-store~=0.0.18 azure-eventgrid~=1.1 @@ -87,6 +87,7 @@ azure-storage-file~=1.3 azure-storage-queue~=1.3 cryptography>=2.1.4 futures +mock typing msal~=0.4.1 msrest>=0.5.0 From 07ad2c3d429d6e37ebfd8673ca37775c3c462ba6 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 5 Aug 2019 11:29:08 -0700 Subject: [PATCH 09/11] update min azure-core dependency across the repo --- sdk/keyvault/azure-keyvault-keys/setup.py | 2 +- sdk/keyvault/azure-keyvault-secrets/setup.py | 2 +- sdk/storage/azure-storage-blob/setup.py | 2 +- sdk/storage/azure-storage-file/setup.py | 2 +- sdk/storage/azure-storage-queue/setup.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk/keyvault/azure-keyvault-keys/setup.py b/sdk/keyvault/azure-keyvault-keys/setup.py index 0ae136fe914d..2bf604c00b14 100644 --- a/sdk/keyvault/azure-keyvault-keys/setup.py +++ b/sdk/keyvault/azure-keyvault-keys/setup.py @@ -77,6 +77,6 @@ "azure", ] ), - install_requires=["azure-core<2.0.0,>=1.0.0b1", "azure-common~=1.1", "msrest>=0.5.0"], + install_requires=["azure-core<2.0.0,>=1.0.0b2", "azure-common~=1.1", "msrest>=0.5.0"], extras_require={":python_version<'3.0'": ["azure-nspkg"], ":python_version<'3.5'": ["typing"]}, ) diff --git a/sdk/keyvault/azure-keyvault-secrets/setup.py b/sdk/keyvault/azure-keyvault-secrets/setup.py index 7ffb60b443c9..271061245994 100644 --- a/sdk/keyvault/azure-keyvault-secrets/setup.py +++ b/sdk/keyvault/azure-keyvault-secrets/setup.py @@ -77,6 +77,6 @@ "azure", ] ), - install_requires=["azure-core<2.0.0,>=1.0.0b1", "azure-common~=1.1", "msrest>=0.5.0"], + install_requires=["azure-core<2.0.0,>=1.0.0b2", "azure-common~=1.1", "msrest>=0.5.0"], extras_require={":python_version<'3.0'": ["azure-nspkg"], ":python_version<'3.5'": ["typing"]}, ) diff --git a/sdk/storage/azure-storage-blob/setup.py b/sdk/storage/azure-storage-blob/setup.py index f64bb70470d0..7edf7eb60aa9 100644 --- a/sdk/storage/azure-storage-blob/setup.py +++ b/sdk/storage/azure-storage-blob/setup.py @@ -91,7 +91,7 @@ 'tests.common' ]), install_requires=[ - "azure-core<2.0.0,>=1.0.0b1", + "azure-core<2.0.0,>=1.0.0b2", "msrest>=0.5.0", "cryptography>=2.1.4" ], diff --git a/sdk/storage/azure-storage-file/setup.py b/sdk/storage/azure-storage-file/setup.py index 0258ff7730ec..0d84ca67c99e 100644 --- a/sdk/storage/azure-storage-file/setup.py +++ b/sdk/storage/azure-storage-file/setup.py @@ -79,7 +79,7 @@ 'tests.common' ]), install_requires=[ - "azure-core<2.0.0,>=1.0.0b1", + "azure-core<2.0.0,>=1.0.0b2", "msrest>=0.5.0", "cryptography>=2.1.4" ], diff --git a/sdk/storage/azure-storage-queue/setup.py b/sdk/storage/azure-storage-queue/setup.py index 4202cdce88c7..85086f8f0260 100644 --- a/sdk/storage/azure-storage-queue/setup.py +++ b/sdk/storage/azure-storage-queue/setup.py @@ -79,7 +79,7 @@ 'tests.common' ]), install_requires=[ - "azure-core<2.0.0,>=1.0.0b1", + "azure-core<2.0.0,>=1.0.0b2", "msrest>=0.5.0", "cryptography>=2.1.4" ], From 71b68af3b20154e4c5b864b798ba74da97df8cd3 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 5 Aug 2019 11:30:33 -0700 Subject: [PATCH 10/11] update history --- sdk/identity/azure-identity/HISTORY.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/identity/azure-identity/HISTORY.md b/sdk/identity/azure-identity/HISTORY.md index 9978d05140fe..d250ff2ed24c 100644 --- a/sdk/identity/azure-identity/HISTORY.md +++ b/sdk/identity/azure-identity/HISTORY.md @@ -1,14 +1,14 @@ # Release History -## 1.0.0b2 +## 1.0.0b2 (2019-08-05) Breaking changes: - Removed `Configuration` from the public API in prepration for entirely kwargs-based configuration. Static `create_config` methods have been renamed `_create_config`, and will be removed entirely in a future release. Dependency changes: -- Updated [`azure-core`](https://pypi.org/project/azure-core/) to 1.0.0b2 -- Updated [MSAL](https://pypi.org/project/msal/) 0.4.1 +- Adopted [`azure-core`](https://pypi.org/project/azure-core/) 1.0.0b2 +- Adopted [MSAL](https://pypi.org/project/msal/) 0.4.1 - New dependency for Python 2.7: [mock](https://pypi.org/project/mock/) New credentials: From 5504fbd342f2f60c18fda85b5200c88009537f79 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 5 Aug 2019 12:15:53 -0700 Subject: [PATCH 11/11] update history again --- sdk/identity/azure-identity/HISTORY.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sdk/identity/azure-identity/HISTORY.md b/sdk/identity/azure-identity/HISTORY.md index d250ff2ed24c..2699bc18381c 100644 --- a/sdk/identity/azure-identity/HISTORY.md +++ b/sdk/identity/azure-identity/HISTORY.md @@ -1,17 +1,19 @@ # Release History ## 1.0.0b2 (2019-08-05) -Breaking changes: -- Removed `Configuration` from the public API in prepration for entirely -kwargs-based configuration. Static `create_config` methods have been renamed -`_create_config`, and will be removed entirely in a future release. +### Breaking changes: +- Removed `azure.core.Configuration` from the public API in preparation for a +revamped configuration API. Static `create_config` methods have been renamed +`_create_config`, and will be removed in a future release. -Dependency changes: -- Adopted [`azure-core`](https://pypi.org/project/azure-core/) 1.0.0b2 +### Dependency changes: +- Adopted [azure-core](https://pypi.org/project/azure-core/) 1.0.0b2 + - If you later want to revert to azure-identity 1.0.0b1, or another Azure SDK + library requiring azure-core 1.0.0b1, you'll need to `pip uninstall azure-core` - Adopted [MSAL](https://pypi.org/project/msal/) 0.4.1 - New dependency for Python 2.7: [mock](https://pypi.org/project/mock/) -New credentials: +### New features: - Added credentials for authenticating users: [`DeviceCodeCredential`](https://azure.github.io/azure-sdk-for-python/ref/azure.identity.html#azure.identity.DeviceCodeCredential), [`InteractiveBrowserCredential`](https://azure.github.io/azure-sdk-for-python/ref/azure.identity.html#azure.identity.InteractiveBrowserCredential),