diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md index 2a276e3a36c5..a122368fe048 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md @@ -2,6 +2,11 @@ ## 1.0.0b3 (Unreleased) +**New features** + +- Authentication using `azure-identity` credentials now supported + - see the [Azure Identity documentation](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/identity/azure-identity/README.md) for more information + ## 1.0.0b2 (2020-05-06) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/README.md b/sdk/formrecognizer/azure-ai-formrecognizer/README.md index c38e74bd645d..d6b6c1fd9be3 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/README.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/README.md @@ -66,24 +66,55 @@ az cognitiveservices account show --name "resource-name" --resource-group "resou ``` #### Types of credentials -The `credential` parameter may be provided as a [AzureKeyCredential][azure-key-credential] from [azure.core][azure_core]. +The `credential` parameter may be provided as a [AzureKeyCredential][azure-key-credential] from [azure.core][azure_core], +or as a credential type from Azure Active Directory. See the full details regarding [authentication][cognitive_authentication] of cognitive services. -To use an [API key][cognitive_authentication_api_key], -pass the key as a string into an instance of `AzureKeyCredential("")`. -The API key can be found in the Azure Portal or by running the following Azure CLI command: - -```az cognitiveservices account keys list --name "resource-name" --resource-group "resource-group-name"``` - -Use the key as the credential parameter to authenticate the client: -```python -from azure.ai.formrecognizer import FormRecognizerClient -from azure.core.credentials import AzureKeyCredential - -endpoint = "https://.api.cognitive.microsoft.com/" -credential = AzureKeyCredential("") -form_recognizer_client = FormRecognizerClient(endpoint, credential) -``` +1. To use an [API key][cognitive_authentication_api_key], + pass the key as a string into an instance of `AzureKeyCredential("")`. + The API key can be found in the Azure Portal or by running the following Azure CLI command: + + ```az cognitiveservices account keys list --name "resource-name" --resource-group "resource-group-name"``` + + Use the key as the credential parameter to authenticate the client: + ```python + from azure.ai.formrecognizer import FormRecognizerClient + from azure.core.credentials import AzureKeyCredential + + endpoint = "https://.api.cognitive.microsoft.com/" + credential = AzureKeyCredential("") + form_recognizer_client = FormRecognizerClient(endpoint, credential) + ``` + +2. To use an [Azure Active Directory (AAD) token credential][cognitive_authentication_aad], + provide an instance of the desired credential type obtained from the + [azure-identity][azure_identity_credentials] library. + Note that regional endpoints do not support AAD authentication. Create a [custom subdomain][custom_subdomain] + name for your resource in order to use this type of authentication. + + Authentication with AAD requires some initial setup: + * [Install azure-identity][install_azure_identity] + * [Register a new AAD application][register_aad_app] + * [Grant access][grant_role_access] to Form Recognizer by assigning the `"Cognitive Services User"` role to your service principal. + + After setup, you can choose which type of [credential][azure_identity_credentials] from azure.identity to use. + As an example, [DefaultAzureCredential][default_azure_credential] + can be used to authenticate the client: + + Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables: + AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET + + Use the returned token credential to authenticate the client: + ```python + from azure.identity import DefaultAzureCredential + from azure.ai.formrecognizer import FormRecognizerClient + token_credential = DefaultAzureCredential() + + form_recognizer_client = FormRecognizerClient( + endpoint="https://.cognitiveservices.azure.com/", + credential=token_credential + ) + ``` ## Key concepts @@ -102,6 +133,7 @@ form_recognizer_client = FormRecognizerClient(endpoint, credential) - Managing models created in your account. Please note that models can also be trained using a graphical user interface such as the [Form Recognizer Labeling Tool][fr-labeling-tool]. + ### Long-Running Operations Long-running operations are operations which consist of an initial request sent to the service to start an operation, followed by polling the service at intervals to determine whether the operation has completed or failed, and if it has @@ -349,6 +381,7 @@ These code samples show common scenario operations with the Azure Form Recognize The async versions of the samples (the python sample files appended with `_async`) show asynchronous operations with Form Recognizer and require Python 3.5 or later. +* Client authentication: [sample_authentication.py][sample_authentication] ([async_version][sample_authentication_async]) * Recognize receipts: [sample_recognize_receipts.py][sample_recognize_receipts] ([async version][sample_recognize_receipts_async]) * Recognize receipts from a URL: [sample_recognize_receipts_from_url.py][sample_recognize_receipts_from_url] ([async version][sample_recognize_receipts_from_url_async]) * Recognize content: [sample_recognize_content.py][sample_recognize_content] ([async version][sample_recognize_content_async]) @@ -410,6 +443,8 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ [coc_contact]: mailto:opencode@microsoft.com +[sample_authentication]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_authentication.py +[sample_authentication_async]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_authentication_async.py [sample_manage_custom_models]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_manage_custom_models.py [sample_manage_custom_models_async]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_manage_custom_models_async.py [sample_recognize_content]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_content.py diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py index 109f5456d179..fafe6671c6fe 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py @@ -10,12 +10,11 @@ Any, IO, Union, - TYPE_CHECKING, + TYPE_CHECKING ) from azure.core.tracing.decorator import distributed_trace from azure.core.polling import LROPoller from azure.core.polling.base_polling import LROBasePolling -from azure.core.pipeline.policies import AzureKeyCredentialPolicy from ._generated._form_recognizer_client import FormRecognizerClient as FormRecognizer from ._response_handlers import ( prepare_us_receipt, @@ -23,12 +22,12 @@ prepare_form_result ) from ._generated.models import AnalyzeOperationResult -from ._helpers import get_content_type, error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER +from ._helpers import get_content_type, get_authentication_policy, error_map, POLLING_INTERVAL from ._user_agent import USER_AGENT from ._polling import AnalyzePolling from ._form_training_client import FormTrainingClient if TYPE_CHECKING: - from azure.core.credentials import AzureKeyCredential + from azure.core.credentials import AzureKeyCredential, TokenCredential class FormRecognizerClient(object): @@ -40,28 +39,39 @@ class FormRecognizerClient(object): :param str endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://westus2.api.cognitive.microsoft.com). :param credential: Credentials needed for the client to connect to Azure. - This is an instance of AzureKeyCredential if using an API key. - :type credential: ~azure.core.credentials.AzureKeyCredential + This is an instance of AzureKeyCredential if using an API key or a token + credential from :mod:`azure.identity`. + :type credential: :class:`~azure.core.credentials.AzureKeyCredential` or + :class:`~azure.core.credentials.TokenCredential` .. admonition:: Example: - .. literalinclude:: ../samples/sample_get_bounding_boxes.py - :start-after: [START create_form_recognizer_client] - :end-before: [END create_form_recognizer_client] + .. literalinclude:: ../samples/sample_authentication.py + :start-after: [START create_fr_client_with_key] + :end-before: [END create_fr_client_with_key] :language: python :dedent: 8 :caption: Creating the FormRecognizerClient with an endpoint and API key. + + .. literalinclude:: ../samples/sample_authentication.py + :start-after: [START create_fr_client_with_aad] + :end-before: [END create_fr_client_with_aad] + :language: python + :dedent: 8 + :caption: Creating the FormRecognizerClient with a token credential. """ def __init__(self, endpoint, credential, **kwargs): - # type: (str, AzureKeyCredential, Any) -> None + # type: (str, Union[AzureKeyCredential, TokenCredential], Any) -> None self._endpoint = endpoint self._credential = credential + + authentication_policy = get_authentication_policy(credential) self._client = FormRecognizer( endpoint=self._endpoint, credential=self._credential, sdk_moniker=USER_AGENT, - authentication_policy=AzureKeyCredentialPolicy(credential, COGNITIVE_KEY_HEADER), + authentication_policy=authentication_policy, **kwargs ) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index e699dbac99ab..281c467c7b9d 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -10,16 +10,16 @@ Optional, Any, Iterable, + Union, TYPE_CHECKING, ) from azure.core.tracing.decorator import distributed_trace from azure.core.polling import LROPoller from azure.core.polling.base_polling import LROBasePolling -from azure.core.pipeline.policies import AzureKeyCredentialPolicy from ._generated.models import Model from ._generated._form_recognizer_client import FormRecognizerClient as FormRecognizer from ._generated.models import TrainRequest, TrainSourceFilter -from ._helpers import error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER +from ._helpers import error_map, get_authentication_policy, POLLING_INTERVAL from ._models import ( CustomFormModelInfo, AccountProperties, @@ -28,7 +28,7 @@ from ._polling import TrainingPolling from ._user_agent import USER_AGENT if TYPE_CHECKING: - from azure.core.credentials import AzureKeyCredential + from azure.core.credentials import AzureKeyCredential, TokenCredential from azure.core.pipeline.transport import HttpResponse PipelineResponseType = HttpResponse @@ -42,26 +42,37 @@ class FormTrainingClient(object): :param str endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://westus2.api.cognitive.microsoft.com). :param credential: Credentials needed for the client to connect to Azure. - This is an instance of AzureKeyCredential if using an API key. - :type credential: ~azure.core.credentials.AzureKeyCredential + This is an instance of AzureKeyCredential if using an API key or a token + credential from :mod:`azure.identity`. + :type credential: :class:`~azure.core.credentials.AzureKeyCredential` or + :class:`~azure.core.credentials.TokenCredential` .. admonition:: Example: - .. literalinclude:: ../samples/sample_train_model_with_labels.py - :start-after: [START create_form_training_client] - :end-before: [END create_form_training_client] + .. literalinclude:: ../samples/sample_authentication.py + :start-after: [START create_ft_client_with_key] + :end-before: [END create_ft_client_with_key] :language: python :dedent: 8 :caption: Creating the FormTrainingClient with an endpoint and API key. + + .. literalinclude:: ../samples/sample_authentication.py + :start-after: [START create_ft_client_with_aad] + :end-before: [END create_ft_client_with_aad] + :language: python + :dedent: 8 + :caption: Creating the FormTrainingClient with a token credential. """ def __init__(self, endpoint, credential, **kwargs): - # type: (str, AzureKeyCredential, Any) -> None + # type: (str, Union[AzureKeyCredential, TokenCredential], Any) -> None + + authentication_policy = get_authentication_policy(credential) self._client = FormRecognizer( endpoint=endpoint, credential=credential, sdk_moniker=USER_AGENT, - authentication_policy=AzureKeyCredentialPolicy(credential, COGNITIVE_KEY_HEADER), + authentication_policy=authentication_policy, **kwargs ) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_helpers.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_helpers.py index c6776aa767db..38e5fd0ae13b 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_helpers.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_helpers.py @@ -5,6 +5,8 @@ # ------------------------------------ import six +from azure.core.credentials import AzureKeyCredential +from azure.core.pipeline.policies import AzureKeyCredentialPolicy from azure.core.exceptions import ( ResourceNotFoundError, ResourceExistsError, @@ -22,6 +24,21 @@ } +def get_authentication_policy(credential): + authentication_policy = None + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if isinstance(credential, AzureKeyCredential): + authentication_policy = AzureKeyCredentialPolicy( + name=COGNITIVE_KEY_HEADER, credential=credential + ) + elif credential is not None and not hasattr(credential, "get_token"): + raise TypeError("Unsupported credential: {}. Use an instance of AzureKeyCredential " + "or a token credential from azure.identity".format(type(credential))) + + return authentication_policy + + def get_content_type(form): """Source: https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files """ diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py index f8c17f3a6c63..278cc52471f9 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py @@ -15,7 +15,6 @@ ) from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.polling.async_base_polling import AsyncLROBasePolling -from azure.core.pipeline.policies import AzureKeyCredentialPolicy from ._form_training_client_async import FormTrainingClient from .._generated.aio._form_recognizer_client_async import FormRecognizerClient as FormRecognizer from .._response_handlers import ( @@ -24,11 +23,12 @@ prepare_form_result ) from .._generated.models import AnalyzeOperationResult -from .._helpers import get_content_type, error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER +from .._helpers import get_content_type, get_authentication_policy, error_map, POLLING_INTERVAL from .._user_agent import USER_AGENT from .._polling import AnalyzePolling if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential + from azure.core.credentials_async import AsyncTokenCredential from .._models import ( USReceipt, FormPage, @@ -45,32 +45,43 @@ class FormRecognizerClient(object): :param str endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://westus2.api.cognitive.microsoft.com). :param credential: Credentials needed for the client to connect to Azure. - This is an instance of AzureKeyCredential if using an API key. - :type credential: ~azure.core.credentials.AzureKeyCredential + This is an instance of AzureKeyCredential if using an API key or a token + credential from :mod:`azure.identity`. + :type credential: :class:`~azure.core.credentials.AzureKeyCredential` + or :class:`~azure.core.credentials_async.AsyncTokenCredential` .. admonition:: Example: - .. literalinclude:: ../samples/async_samples/sample_get_bounding_boxes_async.py - :start-after: [START create_form_recognizer_client_async] - :end-before: [END create_form_recognizer_client_async] + .. literalinclude:: ../samples/async_samples/sample_authentication_async.py + :start-after: [START create_fr_client_with_key_async] + :end-before: [END create_fr_client_with_key_async] :language: python :dedent: 8 :caption: Creating the FormRecognizerClient with an endpoint and API key. + + .. literalinclude:: ../samples/async_samples/sample_authentication_async.py + :start-after: [START create_fr_client_with_aad_async] + :end-before: [END create_fr_client_with_aad_async] + :language: python + :dedent: 8 + :caption: Creating the FormRecognizerClient with a token credential. """ def __init__( self, endpoint: str, - credential: "AzureKeyCredential", + credential: Union["AzureKeyCredential", "AsyncTokenCredential"], **kwargs: Any ) -> None: + + authentication_policy = get_authentication_policy(credential) self._endpoint = endpoint self._credential = credential self._client = FormRecognizer( endpoint=self._endpoint, credential=self._credential, sdk_moniker=USER_AGENT, - authentication_policy=AzureKeyCredentialPolicy(credential, COGNITIVE_KEY_HEADER), + authentication_policy=authentication_policy, **kwargs ) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index 51798412b6bb..86c73bb4598c 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -9,6 +9,7 @@ from typing import ( Optional, Any, + Union, AsyncIterable, TYPE_CHECKING, ) @@ -16,11 +17,10 @@ from azure.core.polling.async_base_polling import AsyncLROBasePolling from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async -from azure.core.pipeline.policies import AzureKeyCredentialPolicy from .._generated.aio._form_recognizer_client_async import FormRecognizerClient as FormRecognizer from .._generated.models import TrainRequest, TrainSourceFilter from .._generated.models import Model -from .._helpers import error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER +from .._helpers import error_map, get_authentication_policy, POLLING_INTERVAL from .._models import ( CustomFormModelInfo, AccountProperties, @@ -30,6 +30,7 @@ from .._polling import TrainingPolling if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential + from azure.core.credentials_async import AsyncTokenCredential class FormTrainingClient(object): @@ -41,30 +42,41 @@ class FormTrainingClient(object): :param str endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://westus2.api.cognitive.microsoft.com). :param credential: Credentials needed for the client to connect to Azure. - This is an instance of AzureKeyCredential if using an API key. - :type credential: ~azure.core.credentials.AzureKeyCredential + This is an instance of AzureKeyCredential if using an API key or a token + credential from :mod:`azure.identity`. + :type credential: :class:`~azure.core.credentials.AzureKeyCredential` + or :class:`~azure.core.credentials_async.AsyncTokenCredential` .. admonition:: Example: - .. literalinclude:: ../samples/async_samples/sample_train_model_with_labels_async.py - :start-after: [START create_form_training_client_async] - :end-before: [END create_form_training_client_async] + .. literalinclude:: ../samples/async_samples/sample_authentication_async.py + :start-after: [START create_ft_client_with_key_async] + :end-before: [END create_ft_client_with_key_async] :language: python :dedent: 8 :caption: Creating the FormTrainingClient with an endpoint and API key. + + .. literalinclude:: ../samples/async_samples/sample_authentication_async.py + :start-after: [START create_ft_client_with_aad_async] + :end-before: [END create_ft_client_with_aad_async] + :language: python + :dedent: 8 + :caption: Creating the FormTrainingClient with a token credential. """ def __init__( self, endpoint: str, - credential: "AzureKeyCredential", + credential: Union["AzureKeyCredential", "AsyncTokenCredential"], **kwargs: Any ) -> None: + + authentication_policy = get_authentication_policy(credential) self._client = FormRecognizer( endpoint=endpoint, credential=credential, sdk_moniker=USER_AGENT, - authentication_policy=AzureKeyCredentialPolicy(credential, COGNITIVE_KEY_HEADER), + authentication_policy=authentication_policy, **kwargs ) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md b/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md index 6ba5a7ebf6b3..8bee2aa4d46e 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md @@ -19,6 +19,7 @@ All of these samples need the endpoint to your Form Recognizer resource ([instru |**File Name**|**Description**| |----------------|-------------| +|[sample_authentication.py][sample_authentication] and [sample_authentication_async.py][sample_authentication_async]|Authenticate the client| |[sample_recognize_content.py][sample_recognize_content] and [sample_recognize_content_async.py][sample_recognize_content_async]|Recognize text and table structures of a document| |[sample_recognize_receipts.py][sample_recognize_receipts] and [sample_recognize_receipts_async.py][sample_recognize_receipts_async]|Recognize data from a file of a US sales receipt using a prebuilt model| |[sample_recognize_receipts_from_url.py][sample_recognize_receipts_from_url] and [sample_recognize_receipts_from_url_async.py][sample_recognize_receipts_from_url_async]|Recognize data from a URL of a US sales receipt using a prebuilt model| @@ -69,6 +70,8 @@ what you can do with the Azure Form Recognizer client library. [get-endpoint-instructions]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/formrecognizer/azure-ai-formrecognizer/README.md#looking-up-the-endpoint [get-key-instructions]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/formrecognizer/azure-ai-formrecognizer/README.md#types-of-credentials +[sample_authentication]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_authentication.py +[sample_authentication_async]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_authentication_async.py [sample_differentiate_output_models_trained_with_and_without_labels]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_differentiate_output_models_trained_with_and_without_labels.py [sample_differentiate_output_models_trained_with_and_without_labels_async]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_differentiate_output_models_trained_with_and_without_labels_async.py [sample_get_bounding_boxes]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_get_bounding_boxes.py diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_authentication_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_authentication_async.py new file mode 100644 index 000000000000..7b5b28c89f65 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_authentication_async.py @@ -0,0 +1,103 @@ +# coding: utf-8 + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +""" +FILE: sample_authentication_async.py + +DESCRIPTION: + This sample demonstrates how to authenticate to the Form Recognizer service. + + There are two supported methods of authentication: + 1) Use a Form Recognizer API key with AzureKeyCredential from azure.core.credentials + 2) Use a token credential from azure-identity to authenticate with Azure Active Directory + + See more details about authentication here: + https://docs.microsoft.com/azure/cognitive-services/authentication + +USAGE: + python sample_authentication_async.py + + Set the environment variables with your own values before running the sample: + 1) AZURE_FORM_RECOGNIZER_ENDPOINT - the endpoint to your Form Recognizer resource. + 2) AZURE_FORM_RECOGNIZER_KEY - your Form Recognizer API key + 3) AZURE_CLIENT_ID - the client ID of your active directory application. + 4) AZURE_TENANT_ID - the tenant ID of your active directory application. + 5) AZURE_CLIENT_SECRET - the secret of your active directory application. +""" + +import os +import asyncio + + +class AuthenticationSampleAsync(object): + + url = "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/sdk/formrecognizer/azure-ai-formrecognizer/tests/sample_forms/receipt/contoso-receipt.png" + + async def authentication_with_api_key_credential_form_recognizer_client_async(self): + # [START create_fr_client_with_key_async] + from azure.core.credentials import AzureKeyCredential + from azure.ai.formrecognizer.aio import FormRecognizerClient + endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + key = os.environ["AZURE_FORM_RECOGNIZER_KEY"] + + form_recognizer_client = FormRecognizerClient(endpoint, AzureKeyCredential(key)) + # [END create_fr_client_with_key_async] + receipt = await form_recognizer_client.recognize_receipts_from_url(self.url) + + async def authentication_with_azure_active_directory_form_recognizer_client_async(self): + """DefaultAzureCredential will use the values from these environment + variables: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET + """ + # [START create_fr_client_with_aad_async] + from azure.ai.formrecognizer.aio import FormRecognizerClient + from azure.identity.aio import DefaultAzureCredential + + endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + credential = DefaultAzureCredential() + + form_recognizer_client = FormRecognizerClient(endpoint, credential) + # [END create_fr_client_with_aad_async] + poller = await form_recognizer_client.recognize_receipts_from_url(self.url) + + async def authentication_with_api_key_credential_form_training_client_async(self): + # [START create_ft_client_with_key_async] + from azure.core.credentials import AzureKeyCredential + from azure.ai.formrecognizer.aio import FormTrainingClient + endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + key = os.environ["AZURE_FORM_RECOGNIZER_KEY"] + + form_training_client = FormTrainingClient(endpoint, AzureKeyCredential(key)) + # [END create_ft_client_with_key_async] + properties = await form_training_client.get_account_properties() + + async def authentication_with_azure_active_directory_form_training_client_async(self): + """DefaultAzureCredential will use the values from these environment + variables: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET + """ + # [START create_ft_client_with_aad_async] + from azure.ai.formrecognizer.aio import FormTrainingClient + from azure.identity.aio import DefaultAzureCredential + + endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + credential = DefaultAzureCredential() + + form_training_client = FormTrainingClient(endpoint, credential) + # [END create_ft_client_with_aad_async] + properties = await form_training_client.get_account_properties() + + +async def main(): + sample = AuthenticationSampleAsync() + await sample.authentication_with_api_key_credential_form_recognizer_client_async() + await sample.authentication_with_azure_active_directory_form_recognizer_client_async() + await sample.authentication_with_api_key_credential_form_training_client_async() + await sample.authentication_with_azure_active_directory_form_training_client_async() + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_authentication.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_authentication.py new file mode 100644 index 000000000000..a5eacf3f0392 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_authentication.py @@ -0,0 +1,100 @@ +# coding: utf-8 + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +""" +FILE: sample_authentication.py + +DESCRIPTION: + This sample demonstrates how to authenticate to the Form Recognizer service. + + There are two supported methods of authentication: + 1) Use a Form Recognizer API key with AzureKeyCredential from azure.core.credentials + 2) Use a token credential from azure-identity to authenticate with Azure Active Directory + + See more details about authentication here: + https://docs.microsoft.com/azure/cognitive-services/authentication + +USAGE: + python sample_authentication.py + + Set the environment variables with your own values before running the sample: + 1) AZURE_FORM_RECOGNIZER_ENDPOINT - the endpoint to your Form Recognizer resource. + 2) AZURE_FORM_RECOGNIZER_KEY - your Form Recognizer API key + 3) AZURE_CLIENT_ID - the client ID of your active directory application. + 4) AZURE_TENANT_ID - the tenant ID of your active directory application. + 5) AZURE_CLIENT_SECRET - the secret of your active directory application. +""" + +import os + + +class AuthenticationSample(object): + + url = "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/sdk/formrecognizer/azure-ai-formrecognizer/tests/sample_forms/receipt/contoso-receipt.png" + + def authentication_with_api_key_credential_form_recognizer_client(self): + # [START create_fr_client_with_key] + from azure.core.credentials import AzureKeyCredential + from azure.ai.formrecognizer import FormRecognizerClient + endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + key = os.environ["AZURE_FORM_RECOGNIZER_KEY"] + + form_recognizer_client = FormRecognizerClient(endpoint, AzureKeyCredential(key)) + # [END create_fr_client_with_key] + poller = form_recognizer_client.begin_recognize_receipts_from_url(self.url) + receipt = poller.result() + + def authentication_with_azure_active_directory_form_recognizer_client(self): + """DefaultAzureCredential will use the values from these environment + variables: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET + """ + # [START create_fr_client_with_aad] + from azure.ai.formrecognizer import FormRecognizerClient + from azure.identity import DefaultAzureCredential + + endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + credential = DefaultAzureCredential() + + form_recognizer_client = FormRecognizerClient(endpoint, credential) + # [END create_fr_client_with_aad] + poller = form_recognizer_client.begin_recognize_receipts_from_url(self.url) + receipt = poller.result() + + def authentication_with_api_key_credential_form_training_client(self): + # [START create_ft_client_with_key] + from azure.core.credentials import AzureKeyCredential + from azure.ai.formrecognizer import FormTrainingClient + endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + key = os.environ["AZURE_FORM_RECOGNIZER_KEY"] + + form_training_client = FormTrainingClient(endpoint, AzureKeyCredential(key)) + # [END create_ft_client_with_key] + properties = form_training_client.get_account_properties() + + def authentication_with_azure_active_directory_form_training_client(self): + """DefaultAzureCredential will use the values from these environment + variables: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET + """ + # [START create_ft_client_with_aad] + from azure.ai.formrecognizer import FormTrainingClient + from azure.identity import DefaultAzureCredential + + endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + credential = DefaultAzureCredential() + + form_training_client = FormTrainingClient(endpoint, credential) + # [END create_ft_client_with_aad] + properties = form_training_client.get_account_properties() + + +if __name__ == '__main__': + sample = AuthenticationSample() + sample.authentication_with_api_key_credential_form_recognizer_client() + sample.authentication_with_azure_active_directory_form_recognizer_client() + sample.authentication_with_api_key_credential_form_training_client() + sample.authentication_with_azure_active_directory_form_training_client() diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py index 4d8e85de0533..d54d5117bfa9 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest from datetime import date, time from azure.core.exceptions import HttpResponseError, ServiceRequestError, ClientAuthenticationError from azure.core.credentials import AzureKeyCredential @@ -15,6 +16,15 @@ class TestReceiptFromUrl(FormRecognizerTest): + @pytest.mark.live_test_only + def test_active_directory_auth(self): + token = self.generate_oauth_token() + endpoint = self.get_oauth_endpoint() + client = FormRecognizerClient(endpoint, token) + poller = client.begin_recognize_receipts_from_url(self.receipt_url_jpg) + result = poller.result() + self.assertIsNotNone(result) + @GlobalFormRecognizerAccountPreparer() def test_receipt_url_bad_endpoint(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): with self.assertRaises(ServiceRequestError): diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py index bf3ca34dfd9c..69530227aa9e 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest from datetime import date, time from azure.core.exceptions import HttpResponseError, ServiceRequestError, ClientAuthenticationError from azure.core.credentials import AzureKeyCredential @@ -16,6 +17,17 @@ class TestReceiptFromUrlAsync(AsyncFormRecognizerTest): + @pytest.mark.live_test_only + @GlobalFormRecognizerAccountPreparer() + async def test_active_directory_auth_async(self): + token = self.generate_oauth_token() + endpoint = self.get_oauth_endpoint() + client = FormRecognizerClient(endpoint, token) + result = await client.recognize_receipts_from_url( + self.receipt_url_jpg + ) + self.assertIsNotNone(result) + @GlobalFormRecognizerAccountPreparer() async def test_receipt_url_bad_endpoint(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): with self.assertRaises(ServiceRequestError): diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py index df55afcfcf62..3e6aa4ae3e60 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py @@ -10,7 +10,7 @@ import os import pytest import re -from azure.core.credentials import AzureKeyCredential +from azure.core.credentials import AzureKeyCredential, AccessToken from devtools_testutils import ( AzureTestCase, AzureMgmtPreparer, @@ -18,7 +18,18 @@ ResourceGroupPreparer, ) from devtools_testutils.cognitiveservices_testcase import CognitiveServicesAccountPreparer -from azure_devtools.scenario_tests import ReplayableTest, AzureTestError +from azure_devtools.scenario_tests import ReplayableTest + + +class FakeTokenCredential(object): + """Protocol for classes able to provide OAuth tokens. + :param str scopes: Lets you specify the type of access needed. + """ + def __init__(self): + self.token = AccessToken("YOU SHALL NOT PASS", 0) + + def get_token(self, *args): + return self.token class FormRecognizerTest(AzureTestCase): @@ -43,6 +54,22 @@ def __init__(self, method_name): self.multipage_invoice_pdf = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "./sample_forms/forms/multipage_invoice1.pdf")) self.unsupported_content_py = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "./conftest.py")) + def get_oauth_endpoint(self): + return self.get_settings_value("FORM_RECOGNIZER_AAD_ENDPOINT") + + def generate_oauth_token(self): + if self.is_live: + from azure.identity import ClientSecretCredential + return ClientSecretCredential( + self.get_settings_value("TENANT_ID"), + self.get_settings_value("CLIENT_ID"), + self.get_settings_value("CLIENT_SECRET"), + ) + return self.generate_fake_token() + + def generate_fake_token(self): + return FakeTokenCredential() + def assertModelTransformCorrect(self, model, actual, unlabeled=False): self.assertEqual(model.model_id, actual.model_info.model_id) self.assertEqual(model.created_on, actual.model_info.created_date_time) diff --git a/sdk/formrecognizer/tests.yml b/sdk/formrecognizer/tests.yml index 100236abaec5..f5b9a82dc104 100644 --- a/sdk/formrecognizer/tests.yml +++ b/sdk/formrecognizer/tests.yml @@ -19,6 +19,7 @@ jobs: AZURE_CLIENT_ID: $(aad-azure-sdk-test-client-id) AZURE_FORM_RECOGNIZER_STORAGE_CONTAINER_SAS_URL: $(python-formrecognizer-test-storage-sas-url) AZURE_FORM_RECOGNIZER_MULTIPAGE_STORAGE_CONTAINER_SAS_URL: $(python-formrecognizer-test-storage-multipage-sas-url) + AZURE_FORM_RECOGNIZER_AAD_ENDPOINT: $(python-formrecognizer-test-aad-endpoint) TEST_MODE: 'RunLiveNoRecord' AZURE_SKIP_LIVE_RECORDING: 'True' AZURE_TEST_RUN_LIVE: 'true'