From e169ed61dcc88c8bd55cdc2a38f5511f2eb54ac8 Mon Sep 17 00:00:00 2001 From: TakaValley <26052497+TakaValley@users.noreply.github.com> Date: Tue, 11 Jun 2024 15:01:14 +0800 Subject: [PATCH 1/2] add service principle auth --- .../AuthenticateWithServicePrincipal.csproj | 19 ++++ .../Program.cs | 58 ++++++++++ .NET(v4.0)/Quickstarts/Program.cs | 1 + .NET(v4.0)/Quickstarts/Quickstarts.csproj | 4 + .../Sample_AnalyzeWithPrebuiltModel.cs | 1 + .../Samples/Sample_ExtractLayout.cs | 1 + .NET(v4.0)/Quickstarts/Samples/Samples.cs | 2 + .../Helper => Utility}/SdkExtension.cs | 2 +- .NET(v4.0)/Utility/Utility.csproj | 13 +++ .../{Quickstarts/Helper => Utility}/Utils.cs | 3 +- .NET(v4.0)/sdk-samples.sln | 20 +++- ...r Authentication With Service Principal.md | 31 ++++++ .../authenticate_with_service_principal.py | 101 ++++++++++++++++++ 13 files changed, 252 insertions(+), 4 deletions(-) create mode 100644 .NET(v4.0)/DocumentIntelligenceWithServicePrincipal/AuthenticateWithServicePrincipal.csproj create mode 100644 .NET(v4.0)/DocumentIntelligenceWithServicePrincipal/Program.cs rename .NET(v4.0)/{Quickstarts/Helper => Utility}/SdkExtension.cs (98%) create mode 100644 .NET(v4.0)/Utility/Utility.csproj rename .NET(v4.0)/{Quickstarts/Helper => Utility}/Utils.cs (99%) create mode 100644 Doc/Prerequisites For Authentication With Service Principal.md create mode 100644 Python(v4.0)/Auth/authenticate_with_service_principal.py diff --git a/.NET(v4.0)/DocumentIntelligenceWithServicePrincipal/AuthenticateWithServicePrincipal.csproj b/.NET(v4.0)/DocumentIntelligenceWithServicePrincipal/AuthenticateWithServicePrincipal.csproj new file mode 100644 index 0000000..8324a82 --- /dev/null +++ b/.NET(v4.0)/DocumentIntelligenceWithServicePrincipal/AuthenticateWithServicePrincipal.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/.NET(v4.0)/DocumentIntelligenceWithServicePrincipal/Program.cs b/.NET(v4.0)/DocumentIntelligenceWithServicePrincipal/Program.cs new file mode 100644 index 0000000..eab95b5 --- /dev/null +++ b/.NET(v4.0)/DocumentIntelligenceWithServicePrincipal/Program.cs @@ -0,0 +1,58 @@ +// 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. +// -------------------------------------------------------------------------- +using Azure; +using Azure.AI.DocumentIntelligence; +using Azure.Identity; +using Utility; + +namespace AuthenticateWithServicePrincipal +{ + internal class Program + { + static async Task Main(string[] args) + { + #region To obtain these parameters, please reference the document in (..\..\Doc\Prerequisites For Authentication With Service Principal.md) + // the endpoint to your Document Intelligence resource. + var docIntelligenceEndpoint = ""; + // your Azure tenant id. + var tenantId = ""; + // the Client Secrets of Microsoft Entra App. + var clientId = ""; + // the Client Secrets of Microsoft Entra App. + var clientSecret = ""; + #endregion + + var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret); + var client = new DocumentIntelligenceClient(new Uri(docIntelligenceEndpoint), clientSecretCredential); + + // sample file online + var url = "https://documentintelligence.ai.azure.com/documents/samples/prebuilt/w2-single.png"; + var content = new AnalyzeDocumentContent + { + UrlSource = new Uri(url) + }; + + // To see the list of all the supported fields returned by service and its corresponding types for each supported model, + // access https://aka.ms/di-prebuilt please. + Operation operation = await client.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-tax.us.w2", content); + AnalyzeResult result = operation.Value; + + // Extract DocumentField: + for (int i = 0; i < result.Documents.Count; i++) + { + Console.WriteLine($"Document {i}:"); + + AnalyzedDocument document = result.Documents[i]; + + foreach (var item in document.Fields) + { + Utils.ExtractValueFromDocumentField(item.Key, item.Value); + } + } + } + } +} diff --git a/.NET(v4.0)/Quickstarts/Program.cs b/.NET(v4.0)/Quickstarts/Program.cs index 40056b6..fc00ecb 100644 --- a/.NET(v4.0)/Quickstarts/Program.cs +++ b/.NET(v4.0)/Quickstarts/Program.cs @@ -8,6 +8,7 @@ using ConsoleTables; using System.Configuration; using System.Diagnostics; +using Utility; namespace Quickstarts { diff --git a/.NET(v4.0)/Quickstarts/Quickstarts.csproj b/.NET(v4.0)/Quickstarts/Quickstarts.csproj index 5e6861e..3896b5e 100644 --- a/.NET(v4.0)/Quickstarts/Quickstarts.csproj +++ b/.NET(v4.0)/Quickstarts/Quickstarts.csproj @@ -17,6 +17,10 @@ + + + + diff --git a/.NET(v4.0)/Quickstarts/Samples/Sample_AnalyzeWithPrebuiltModel.cs b/.NET(v4.0)/Quickstarts/Samples/Sample_AnalyzeWithPrebuiltModel.cs index eb36901..1eb2a15 100644 --- a/.NET(v4.0)/Quickstarts/Samples/Sample_AnalyzeWithPrebuiltModel.cs +++ b/.NET(v4.0)/Quickstarts/Samples/Sample_AnalyzeWithPrebuiltModel.cs @@ -7,6 +7,7 @@ using Azure; using Azure.AI.DocumentIntelligence; +using Utility; namespace Quickstarts { diff --git a/.NET(v4.0)/Quickstarts/Samples/Sample_ExtractLayout.cs b/.NET(v4.0)/Quickstarts/Samples/Sample_ExtractLayout.cs index 035be5a..1fbd33f 100644 --- a/.NET(v4.0)/Quickstarts/Samples/Sample_ExtractLayout.cs +++ b/.NET(v4.0)/Quickstarts/Samples/Sample_ExtractLayout.cs @@ -8,6 +8,7 @@ using Azure; using Azure.AI.DocumentIntelligence; using ConsoleTables; +using Utility; namespace Quickstarts { diff --git a/.NET(v4.0)/Quickstarts/Samples/Samples.cs b/.NET(v4.0)/Quickstarts/Samples/Samples.cs index 39fcda2..57f81f2 100644 --- a/.NET(v4.0)/Quickstarts/Samples/Samples.cs +++ b/.NET(v4.0)/Quickstarts/Samples/Samples.cs @@ -4,6 +4,8 @@ // Licensed under the MIT License. See License.txt in the project root for // license information. // -------------------------------------------------------------------------- +using Utility; + namespace Quickstarts { internal partial class Samples(string docIntelligenceEndPoint, string docIntelligenceApiKey) diff --git a/.NET(v4.0)/Quickstarts/Helper/SdkExtension.cs b/.NET(v4.0)/Utility/SdkExtension.cs similarity index 98% rename from .NET(v4.0)/Quickstarts/Helper/SdkExtension.cs rename to .NET(v4.0)/Utility/SdkExtension.cs index cf1b249..bc26e0b 100644 --- a/.NET(v4.0)/Quickstarts/Helper/SdkExtension.cs +++ b/.NET(v4.0)/Utility/SdkExtension.cs @@ -6,7 +6,7 @@ // -------------------------------------------------------------------------- using Azure.AI.DocumentIntelligence; -namespace Quickstarts +namespace Utility { public static class SdkExtension { diff --git a/.NET(v4.0)/Utility/Utility.csproj b/.NET(v4.0)/Utility/Utility.csproj new file mode 100644 index 0000000..bcfb848 --- /dev/null +++ b/.NET(v4.0)/Utility/Utility.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/.NET(v4.0)/Quickstarts/Helper/Utils.cs b/.NET(v4.0)/Utility/Utils.cs similarity index 99% rename from .NET(v4.0)/Quickstarts/Helper/Utils.cs rename to .NET(v4.0)/Utility/Utils.cs index 8669ee8..27bf66b 100644 --- a/.NET(v4.0)/Quickstarts/Helper/Utils.cs +++ b/.NET(v4.0)/Utility/Utils.cs @@ -4,10 +4,9 @@ // Licensed under the MIT License. See License.txt in the project root for // license information. // -------------------------------------------------------------------------- - using Azure.AI.DocumentIntelligence; -namespace Quickstarts +namespace Utility { public class Utils { diff --git a/.NET(v4.0)/sdk-samples.sln b/.NET(v4.0)/sdk-samples.sln index 19ef797..6773141 100644 --- a/.NET(v4.0)/sdk-samples.sln +++ b/.NET(v4.0)/sdk-samples.sln @@ -9,7 +9,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sample Code Snippet For Doc EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeSnippetForApiVer_2024-02-29_Preview", "CodeSnippetForApiVer_2024-02-29_Preview\CodeSnippetForApiVer_2024-02-29_Preview.csproj", "{EFCE60E7-6544-443C-8C68-53BFC9447B51}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeSnippetForApiVer_2023-10-31_Preview", "CodeSnippetForApiVer_2023-10-31_Preview\CodeSnippetForApiVer_2023-10-31_Preview.csproj", "{BC2D5C4C-C70E-4FB1-AD1E-1505F97FF231}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeSnippetForApiVer_2023-10-31_Preview", "CodeSnippetForApiVer_2023-10-31_Preview\CodeSnippetForApiVer_2023-10-31_Preview.csproj", "{BC2D5C4C-C70E-4FB1-AD1E-1505F97FF231}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Auth", "Auth", "{A216036E-43B5-4ABD-B4D4-6B2C5E1B6E7B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthenticateWithServicePrincipal", "DocumentIntelligenceWithServicePrincipal\AuthenticateWithServicePrincipal.csproj", "{4116A237-4981-4BF8-BE47-AC0A1CAB0EEC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common.Library", "Common.Library", "{50D0F7B2-DA35-4966-84EE-62B5002EA513}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utility", "Utility\Utility.csproj", "{CB79733C-D8D1-4603-A58A-E3BF0F27FB38}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -29,6 +37,14 @@ Global {BC2D5C4C-C70E-4FB1-AD1E-1505F97FF231}.Debug|Any CPU.Build.0 = Debug|Any CPU {BC2D5C4C-C70E-4FB1-AD1E-1505F97FF231}.Release|Any CPU.ActiveCfg = Release|Any CPU {BC2D5C4C-C70E-4FB1-AD1E-1505F97FF231}.Release|Any CPU.Build.0 = Release|Any CPU + {4116A237-4981-4BF8-BE47-AC0A1CAB0EEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4116A237-4981-4BF8-BE47-AC0A1CAB0EEC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4116A237-4981-4BF8-BE47-AC0A1CAB0EEC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4116A237-4981-4BF8-BE47-AC0A1CAB0EEC}.Release|Any CPU.Build.0 = Release|Any CPU + {CB79733C-D8D1-4603-A58A-E3BF0F27FB38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB79733C-D8D1-4603-A58A-E3BF0F27FB38}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB79733C-D8D1-4603-A58A-E3BF0F27FB38}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB79733C-D8D1-4603-A58A-E3BF0F27FB38}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -36,6 +52,8 @@ Global GlobalSection(NestedProjects) = preSolution {EFCE60E7-6544-443C-8C68-53BFC9447B51} = {E9CBB1EB-6D19-4981-A5F2-EFEA3CF0F0A7} {BC2D5C4C-C70E-4FB1-AD1E-1505F97FF231} = {E9CBB1EB-6D19-4981-A5F2-EFEA3CF0F0A7} + {4116A237-4981-4BF8-BE47-AC0A1CAB0EEC} = {A216036E-43B5-4ABD-B4D4-6B2C5E1B6E7B} + {CB79733C-D8D1-4603-A58A-E3BF0F27FB38} = {50D0F7B2-DA35-4966-84EE-62B5002EA513} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5CBC567B-C775-4E10-BCB4-E019111881C4} diff --git a/Doc/Prerequisites For Authentication With Service Principal.md b/Doc/Prerequisites For Authentication With Service Principal.md new file mode 100644 index 0000000..0afbbc9 --- /dev/null +++ b/Doc/Prerequisites For Authentication With Service Principal.md @@ -0,0 +1,31 @@ +# Prerequisites For Authentication With Service Principal + +In this article, you'll learn how to create Azure AI Service, Microsoft Entra application and service principal that can be used with role-based access control (RBAC). When you register a new application in Microsoft Entra ID, a service principal is automatically created for the app registration. The service principal is the app's identity in the Microsoft Entra tenant. Access to resources is restricted by the roles assigned to the service principal, giving you control over which resources can be accessed and at which level. + +## Create Azure AI Service +Create a [single-service](https://aka.ms/single-service) or [multi-service](https://aka.ms/multi-service) resource. You can use the free pricing tier (F0) to try the service and upgrade to a paid tier for production later. + +## Register an application with Microsoft Entra ID and create a service principal +For this process, it could reference the [doc section](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#register-an-application-with-microsoft-entra-id-and-create-a-service-principal) completely. + +## Assign a role to the application +1. Sign in to the [Azure portal](https://portal.azure.com/). +2. Select the Azure AI Service which created in previous steps. +3. Select **Access control (IAM)**. +4. Select **Add**, then select **Add role assignment**. +5. In the **Role** tab, select the **"Cognitive Services User"** +6. Select Next. +7. On the **Members** tab, for **Assign access to**, select **User, group, or service principal**. +8. Select **Select members**. By default, Microsoft Entra applications aren't displayed in the available options. To find your application, search for it by the name which register in previous steps. +9. Select the Select button, then select Review + assign. + +## Set up authentication +Reference the [document](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#set-up-authentication), there're three options to set up authentication. +For the sample in repo, it's used [option 3](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#option-3-create-a-new-client-secret). + +So far, all the parameters will be used in the sample programs, it could be obtained from above resouces. +1) DOCUMENTINTELLIGENCE_ENDPOINT - the endpoint to your Document Intelligence resource. +2) DOCUMENTINTELLIGENCE_TENANT_ID - your Azure tenant id. +3) DOCUMENTINTELLIGENCE_CLIENT_ID - the Application (client) ID of Microsoft Entra App. +4) DOCUMENTINTELLIGENCE_CLIENT_SECRET - the Client Secrets of Microsoft Entra App. + diff --git a/Python(v4.0)/Auth/authenticate_with_service_principal.py b/Python(v4.0)/Auth/authenticate_with_service_principal.py new file mode 100644 index 0000000..312dc6f --- /dev/null +++ b/Python(v4.0)/Auth/authenticate_with_service_principal.py @@ -0,0 +1,101 @@ +# 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: authenticate_with_service_principal.py + +DESCRIPTION: + This sample demonstrates how to analyze document with Client Secret Credential. + +PREREQUISITES: +Set the environment variables with your own values before running the sample: + 1) DOCUMENTINTELLIGENCE_ENDPOINT - the endpoint to your Document Intelligence resource. + 2) DOCUMENTINTELLIGENCE_TENANT_ID - your Azure tenant id. + 3) DOCUMENTINTELLIGENCE_CLIENT_ID - the Application (client) ID of Microsoft Entra App. + 4) DOCUMENTINTELLIGENCE_CLIENT_SECRET - the Client Secrets of Microsoft Entra App. + +To obtain these parameters, please reference the document in (..\\..\\Doc\\Prerequisites For Authentication With Service Principal.md) + +USAGE: + python authenticate_with_service_principal.py +""" + +import os +from azure.ai.documentintelligence import DocumentIntelligenceClient +from azure.ai.documentintelligence.models import ( + AnalyzeResult, + AnalyzeDocumentRequest, +) +from azure.core.exceptions import HttpResponseError +from azure.identity import ClientSecretCredential +from dotenv import find_dotenv, load_dotenv + + +def authenticate_with_service_principal(): + endpoint = os.environ["DOCUMENTINTELLIGENCE_ENDPOINT"] + tenant_id = os.environ["DOCUMENTINTELLIGENCE_TENANT_ID"] + client_id = os.environ["DOCUMENTINTELLIGENCE_CLIENT_ID"] + client_secret = os.environ["DOCUMENTINTELLIGENCE_CLIENT_SECRET"] + + client_secret_credential = ClientSecretCredential( + tenant_id, client_id, client_secret + ) + + document_intelligence_client = DocumentIntelligenceClient( + endpoint=endpoint, credential=client_secret_credential + ) + + poller = document_intelligence_client.begin_analyze_document( + "prebuilt-tax.us.w2", + AnalyzeDocumentRequest( + url_source="https://documentintelligence.ai.azure.com/documents/samples/prebuilt/w2-single.png" + ), + ) + + result: AnalyzeResult = poller.result() + + if result.documents: + for idx, document in enumerate(result.documents): + print(f"--------Analyzing document #{idx + 1}--------") + print(f"Document has type {document.doc_type}") + print(f"Document has document type confidence {document.confidence}") + print(f"Document was analyzed with model with ID {result.model_id}") + if document.fields: + for name, field in document.fields.items(): + field_value = ( + field.get("valueString") + if field.get("valueString") + else field.content + ) + print( + f"......found field of type '{field.type}' with value '{field_value}' and with confidence {field.confidence}" + ) + + print("----------------------------------------") + + +if __name__ == "__main__": + + try: + load_dotenv(find_dotenv()) + authenticate_with_service_principal() + except HttpResponseError as error: + # Examples of how to check an HttpResponseError + # Check by error code: + if error.error is not None: + if error.error.code == "InvalidImage": + print(f"Received an invalid image error: {error.error}") + if error.error.code == "InvalidRequest": + print(f"Received an invalid request error: {error.error}") + # Raise the error again after printing it + raise + # If the inner error is None and then it is possible to check the message to get more information: + if "Invalid request".casefold() in error.message.casefold(): + print(f"Uh-oh! Seems there was an invalid request: {error}") + # Raise the error again + raise From 3ffbe70ae58a4446d234d82a3cc9f6903d81338e Mon Sep 17 00:00:00 2001 From: TakaValley <26052497+TakaValley@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:46:59 +0800 Subject: [PATCH 2/2] Add user-assigned managed identity --- ...cateWithUserAssignedManagedIdentity.csproj | 19 ++++ .../Program.cs | 49 ++++++++++ .../AuthenticateWithServicePrincipal.csproj | 2 +- .NET(v4.0)/sdk-samples.sln | 7 ++ ...r Authentication With Service Principal.md | 2 +- ...ion With User-Assigned Managed Identity.md | 22 +++++ ...ate_with_user-assigned_managed_identity.py | 91 +++++++++++++++++++ 7 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 .NET(v4.0)/AuthenticateWithUserAssignedManagedIdentity/AuthenticateWithUserAssignedManagedIdentity.csproj create mode 100644 .NET(v4.0)/AuthenticateWithUserAssignedManagedIdentity/Program.cs create mode 100644 Doc/Prerequisites For Authentication With User-Assigned Managed Identity.md create mode 100644 Python(v4.0)/Auth/authenticate_with_user-assigned_managed_identity.py diff --git a/.NET(v4.0)/AuthenticateWithUserAssignedManagedIdentity/AuthenticateWithUserAssignedManagedIdentity.csproj b/.NET(v4.0)/AuthenticateWithUserAssignedManagedIdentity/AuthenticateWithUserAssignedManagedIdentity.csproj new file mode 100644 index 0000000..1b5fcbd --- /dev/null +++ b/.NET(v4.0)/AuthenticateWithUserAssignedManagedIdentity/AuthenticateWithUserAssignedManagedIdentity.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/.NET(v4.0)/AuthenticateWithUserAssignedManagedIdentity/Program.cs b/.NET(v4.0)/AuthenticateWithUserAssignedManagedIdentity/Program.cs new file mode 100644 index 0000000..8c13d30 --- /dev/null +++ b/.NET(v4.0)/AuthenticateWithUserAssignedManagedIdentity/Program.cs @@ -0,0 +1,49 @@ +// 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. +// -------------------------------------------------------------------------- +using Azure; +using Azure.AI.DocumentIntelligence; +using Azure.Identity; +using Utility; +namespace AuthenticateWithUserAssignedManagedIdentity +{ + internal class Program + { + static async Task Main(string[] args) + { + // The endpoint to your Document Intelligence resource. + // To obtain the parameter, please reference the document + // in (..\..\Doc\Prerequisites For Authentication With User-Assigned Managed Identity.md) + var docIntelligenceEndpoint = ""; + var client = new DocumentIntelligenceClient(new Uri(docIntelligenceEndpoint), new DefaultAzureCredential()); + + // sample file online + var url = "https://documentintelligence.ai.azure.com/documents/samples/prebuilt/w2-single.png"; + var content = new AnalyzeDocumentContent + { + UrlSource = new Uri(url) + }; + + // To see the list of all the supported fields returned by service and its corresponding types for each supported model, + // access https://aka.ms/di-prebuilt please. + Operation operation = await client.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-tax.us.w2", content); + AnalyzeResult result = operation.Value; + + // Extract DocumentField: + for (int i = 0; i < result.Documents.Count; i++) + { + Console.WriteLine($"Document {i}:"); + + AnalyzedDocument document = result.Documents[i]; + + foreach (var item in document.Fields) + { + Utils.ExtractValueFromDocumentField(item.Key, item.Value); + } + } + } + } +} diff --git a/.NET(v4.0)/DocumentIntelligenceWithServicePrincipal/AuthenticateWithServicePrincipal.csproj b/.NET(v4.0)/DocumentIntelligenceWithServicePrincipal/AuthenticateWithServicePrincipal.csproj index 8324a82..1b5fcbd 100644 --- a/.NET(v4.0)/DocumentIntelligenceWithServicePrincipal/AuthenticateWithServicePrincipal.csproj +++ b/.NET(v4.0)/DocumentIntelligenceWithServicePrincipal/AuthenticateWithServicePrincipal.csproj @@ -9,7 +9,7 @@ - + diff --git a/.NET(v4.0)/sdk-samples.sln b/.NET(v4.0)/sdk-samples.sln index 6773141..1202509 100644 --- a/.NET(v4.0)/sdk-samples.sln +++ b/.NET(v4.0)/sdk-samples.sln @@ -19,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common.Library", "Common.Li EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utility", "Utility\Utility.csproj", "{CB79733C-D8D1-4603-A58A-E3BF0F27FB38}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthenticateWithUserAssignedManagedIdentity", "AuthenticateWithUserAssignedManagedIdentity\AuthenticateWithUserAssignedManagedIdentity.csproj", "{609B2281-6798-4D39-906D-51B29C0E3588}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {CB79733C-D8D1-4603-A58A-E3BF0F27FB38}.Debug|Any CPU.Build.0 = Debug|Any CPU {CB79733C-D8D1-4603-A58A-E3BF0F27FB38}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB79733C-D8D1-4603-A58A-E3BF0F27FB38}.Release|Any CPU.Build.0 = Release|Any CPU + {609B2281-6798-4D39-906D-51B29C0E3588}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {609B2281-6798-4D39-906D-51B29C0E3588}.Debug|Any CPU.Build.0 = Debug|Any CPU + {609B2281-6798-4D39-906D-51B29C0E3588}.Release|Any CPU.ActiveCfg = Release|Any CPU + {609B2281-6798-4D39-906D-51B29C0E3588}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -54,6 +60,7 @@ Global {BC2D5C4C-C70E-4FB1-AD1E-1505F97FF231} = {E9CBB1EB-6D19-4981-A5F2-EFEA3CF0F0A7} {4116A237-4981-4BF8-BE47-AC0A1CAB0EEC} = {A216036E-43B5-4ABD-B4D4-6B2C5E1B6E7B} {CB79733C-D8D1-4603-A58A-E3BF0F27FB38} = {50D0F7B2-DA35-4966-84EE-62B5002EA513} + {609B2281-6798-4D39-906D-51B29C0E3588} = {A216036E-43B5-4ABD-B4D4-6B2C5E1B6E7B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5CBC567B-C775-4E10-BCB4-E019111881C4} diff --git a/Doc/Prerequisites For Authentication With Service Principal.md b/Doc/Prerequisites For Authentication With Service Principal.md index 0afbbc9..f275ae8 100644 --- a/Doc/Prerequisites For Authentication With Service Principal.md +++ b/Doc/Prerequisites For Authentication With Service Principal.md @@ -9,7 +9,7 @@ Create a [single-service](https://aka.ms/single-service) or [multi-service](http For this process, it could reference the [doc section](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#register-an-application-with-microsoft-entra-id-and-create-a-service-principal) completely. ## Assign a role to the application -1. Sign in to the [Azure portal](https://portal.azure.com/). +1. Sign in to the [Azure portal](https://portal.azure.com/) with administrator privileges. 2. Select the Azure AI Service which created in previous steps. 3. Select **Access control (IAM)**. 4. Select **Add**, then select **Add role assignment**. diff --git a/Doc/Prerequisites For Authentication With User-Assigned Managed Identity.md b/Doc/Prerequisites For Authentication With User-Assigned Managed Identity.md new file mode 100644 index 0000000..1b68858 --- /dev/null +++ b/Doc/Prerequisites For Authentication With User-Assigned Managed Identity.md @@ -0,0 +1,22 @@ +# Prerequisites For Authentication With User-Assigned Managed Identity + +In this article, you'll learn how to create Azure AI Service, and administrators can assign a role to an user-assigned managed identity. + +## Create Azure AI Service +Create a [single-service](https://aka.ms/single-service) or [multi-service](https://aka.ms/multi-service) resource. You can use the free pricing tier (F0) to try the service and upgrade to a paid tier for production later. + +## Assign A Role to User By Administrator +1. Sign in to the [Azure portal](https://portal.azure.com/) with administrator privileges. +2. Select the Azure AI Service which created in previous steps. +3. Select **Access control (IAM)**. +4. Select **Add**, then select **Add role assignment**. +5. In the **Role** tab, select the **"Cognitive Services User"** +6. Select Next. +7. On the **Members** tab, for **Assign access to**, select **User, group, or service principal**. +8. Select **Select members**, and choose the user who should have the role assigned. +9. Select the "Select" button, then select "Review + assign". + +So far, the parameters will be used in the sample programs, it could be obtained from above resouces. +1) DOCUMENTINTELLIGENCE_ENDPOINT - the endpoint to your Document Intelligence resource. + + diff --git a/Python(v4.0)/Auth/authenticate_with_user-assigned_managed_identity.py b/Python(v4.0)/Auth/authenticate_with_user-assigned_managed_identity.py new file mode 100644 index 0000000..8c12166 --- /dev/null +++ b/Python(v4.0)/Auth/authenticate_with_user-assigned_managed_identity.py @@ -0,0 +1,91 @@ +# 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: authenticate_with_user-assigned_managed_identity.py + +DESCRIPTION: + This sample demonstrates how to analyze document with user-assigned managed identity. + +PREREQUISITES: +Set the environment variables with your own values before running the sample: + 1) DOCUMENTINTELLIGENCE_ENDPOINT - the endpoint to your Document Intelligence resource. + +To obtain these parameters, please reference the document in (..\\..\\Doc\\Prerequisites For Authentication With User-Assigned Managed Identity.md) + +USAGE: + python authenticate_with_user-assigned_managed_identity.py +""" + +import os +from azure.ai.documentintelligence import DocumentIntelligenceClient +from azure.ai.documentintelligence.models import ( + AnalyzeResult, + AnalyzeDocumentRequest, +) +from azure.core.exceptions import HttpResponseError +from azure.identity import DefaultAzureCredential +from dotenv import find_dotenv, load_dotenv + + +def authenticate_with_service_principal(): + endpoint = os.environ["DOCUMENTINTELLIGENCE_ENDPOINT"] + + document_intelligence_client = DocumentIntelligenceClient( + endpoint=endpoint, credential=DefaultAzureCredential() + ) + + poller = document_intelligence_client.begin_analyze_document( + "prebuilt-tax.us.w2", + AnalyzeDocumentRequest( + url_source="https://documentintelligence.ai.azure.com/documents/samples/prebuilt/w2-single.png" + ), + ) + + result: AnalyzeResult = poller.result() + + if result.documents: + for idx, document in enumerate(result.documents): + print(f"--------Analyzing document #{idx + 1}--------") + print(f"Document has type {document.doc_type}") + print(f"Document has document type confidence {document.confidence}") + print(f"Document was analyzed with model with ID {result.model_id}") + if document.fields: + for name, field in document.fields.items(): + field_value = ( + field.get("valueString") + if field.get("valueString") + else field.content + ) + print( + f"......found field of type '{field.type}' with value '{field_value}' and with confidence {field.confidence}" + ) + + print("----------------------------------------") + + +if __name__ == "__main__": + + try: + load_dotenv(find_dotenv()) + authenticate_with_service_principal() + except HttpResponseError as error: + # Examples of how to check an HttpResponseError + # Check by error code: + if error.error is not None: + if error.error.code == "InvalidImage": + print(f"Received an invalid image error: {error.error}") + if error.error.code == "InvalidRequest": + print(f"Received an invalid request error: {error.error}") + # Raise the error again after printing it + raise + # If the inner error is None and then it is possible to check the message to get more information: + if "Invalid request".casefold() in error.message.casefold(): + print(f"Uh-oh! Seems there was an invalid request: {error}") + # Raise the error again + raise