From fdf7fd83465a52e46ccf486b40f7e772144ec5c7 Mon Sep 17 00:00:00 2001 From: waabsuea Date: Thu, 16 May 2024 03:57:47 +0200 Subject: [PATCH 1/4] Support using cert with Azure function --- .../AzureFunctionsAuthentication.Codeunit.al | 19 +++++ .../AzureFunctionsOAuth2Cert.Codeunit.al | 76 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al diff --git a/src/System Application/App/Azure Function/AzureFunctionsAuthentication.Codeunit.al b/src/System Application/App/Azure Function/AzureFunctionsAuthentication.Codeunit.al index 1a80bc1de0..c767c8687a 100644 --- a/src/System Application/App/Azure Function/AzureFunctionsAuthentication.Codeunit.al +++ b/src/System Application/App/Azure Function/AzureFunctionsAuthentication.Codeunit.al @@ -72,4 +72,23 @@ codeunit 7800 "Azure Functions Authentication" exit(AzureFunctionsCodeAuth); end; + /// + /// Creates an instance of OAuth2 authentication with certificate of Azure function interface. + /// + /// Azure function endpoint + /// Azure function authentication code, empty if anonymous. + /// The Application (client) ID that the Azure portal – App registrations experience assigned to your app. + /// The Application (client) certificate configured in the Azure Portal. + /// The identity authorization provider URL. + /// The redirectURL of your app, for azure function this could be empty + /// The scope for the token, example: "api:///.default" + /// Instance of Azure function response object. + [NonDebuggable] + procedure CreateOAuth2WithCert(Endpoint: Text; AuthenticationCode: Text; ClientId: Text; Cert: SecretText; OAuthAuthorityUrl: Text; RedirectURL: Text; Scope: Text): Interface "Azure Functions Authentication" + var + AzureFunctionsOAuth2Cert: Codeunit "Azure Functions OAuth2 Cert"; + begin + AzureFunctionsOAuth2Cert.SetAuthParameters(Endpoint, AuthenticationCode, ClientId, Cert, OAuthAuthorityUrl, RedirectURL, Scope); + exit(AzureFunctionsOAuth2Cert); + end; } \ No newline at end of file diff --git a/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al b/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al new file mode 100644 index 0000000000..2cac3c6179 --- /dev/null +++ b/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al @@ -0,0 +1,76 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace System.Azure.Functions; + +using System.Utilities; +using System.Security.Authentication; +using System.Telemetry; + +codeunit 7807 "Azure Functions OAuth2 Cert" implements "Azure Functions Authentication" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + var + [NonDebuggable] + AuthenticationCodeGlobal, EndpointGlobal : Text; + [NonDebuggable] + ClientIdGlobal, OAuthAuthorityUrlGlobal, RedirectURLGlobal, ScopeGlobal : Text; + CertGlobal: SecretText; + AccessToken: SecretText; + Scopes: List of [Text]; + BearerLbl: Label 'Bearer %1', Comment = '%1 is the access token', Locked = true; + FailedToGetTokenErr: Label 'Authorization failed to Azure function: %1', Locked = true; + AzureFunctionCategoryLbl: Label 'Connect to Azure Functions', Locked = true; + + [NonDebuggable] + procedure Authenticate(var RequestMessage: HttpRequestMessage): Boolean + var + Uri: Codeunit Uri; + OAuth2: Codeunit OAuth2; + UriBuilder: Codeunit "Uri Builder"; + FeatureTelemetry: Codeunit "Feature Telemetry"; + Headers: HttpHeaders; + Dimensions: Dictionary of [Text, Text]; + IdToken: Text; + begin + UriBuilder.Init(EndpointGlobal); + Scopes.Add(ScopeGlobal); + + OAuth2.AcquireTokensWithCertificate(ClientIdGlobal, CertGlobal, RedirectURLGlobal, OAuthAuthorityUrlGlobal, Scopes, AccessToken, IdToken); + + if AccessToken.IsEmpty() then begin + UriBuilder.GetUri(Uri); + Dimensions.Add('FunctionHost', Format(Uri.GetHost())); + FeatureTelemetry.LogError('0000I75', AzureFunctionCategoryLbl, 'Acquiring token', StrSubstNo(FailedToGetTokenErr, Uri.GetHost()), '', Dimensions); + exit(false); + end; + + RequestMessage.GetHeaders(Headers); + Headers.Remove('Authorization'); + Headers.Add('Authorization', SecretStrSubstNo(BearerLbl, AccessToken)); + + if AuthenticationCodeGlobal <> '' then + UriBuilder.AddQueryParameter('Code', AuthenticationCodeGlobal); + + UriBuilder.GetUri(Uri); + RequestMessage.SetRequestUri(Uri.GetAbsoluteUri()); + exit(true); + end; + + [NonDebuggable] + procedure SetAuthParameters(Endpoint: Text; AuthenticationCode: Text; ClientId: Text; Cert: SecretText; OAuthAuthorityUrl: Text; RedirectURL: Text; Scope: Text) + begin + EndpointGlobal := Endpoint; + AuthenticationCodeGlobal := AuthenticationCode; + ClientIdGlobal := ClientId; + CertGlobal := Cert; + OAuthAuthorityUrlGlobal := OAuthAuthorityUrl; + RedirectURLGlobal := RedirectURL; + ScopeGlobal := Scope; + end; +} \ No newline at end of file From 734210ba98ee034863de3da6811d7cc06751e071 Mon Sep 17 00:00:00 2001 From: Sun Haoran Date: Tue, 21 May 2024 11:41:13 +0200 Subject: [PATCH 2/4] fix error in XML comment --- .../App/Azure Function/AzureFunctionsAuthentication.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System Application/App/Azure Function/AzureFunctionsAuthentication.Codeunit.al b/src/System Application/App/Azure Function/AzureFunctionsAuthentication.Codeunit.al index c767c8687a..dbaa48f995 100644 --- a/src/System Application/App/Azure Function/AzureFunctionsAuthentication.Codeunit.al +++ b/src/System Application/App/Azure Function/AzureFunctionsAuthentication.Codeunit.al @@ -81,7 +81,7 @@ codeunit 7800 "Azure Functions Authentication" /// The Application (client) certificate configured in the Azure Portal. /// The identity authorization provider URL. /// The redirectURL of your app, for azure function this could be empty - /// The scope for the token, example: "api:///.default" + /// The scope for the token, example: "api://(app id)/.default" /// Instance of Azure function response object. [NonDebuggable] procedure CreateOAuth2WithCert(Endpoint: Text; AuthenticationCode: Text; ClientId: Text; Cert: SecretText; OAuthAuthorityUrl: Text; RedirectURL: Text; Scope: Text): Interface "Azure Functions Authentication" From cb03eea638ac8f63ef0e9ab1aba968229e85d5ee Mon Sep 17 00:00:00 2001 From: Wael <38723677+WaelAbuSeada@users.noreply.github.com> Date: Tue, 21 May 2024 12:43:02 +0200 Subject: [PATCH 3/4] Update src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al Co-authored-by: Sun Haoran --- .../App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al b/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al index 2cac3c6179..1ccf629f62 100644 --- a/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al +++ b/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al @@ -23,7 +23,7 @@ codeunit 7807 "Azure Functions OAuth2 Cert" implements "Azure Functions Authenti CertGlobal: SecretText; AccessToken: SecretText; Scopes: List of [Text]; - BearerLbl: Label 'Bearer %1', Comment = '%1 is the access token', Locked = true; + BearerLbl: Label 'Bearer %1', Locked = true; FailedToGetTokenErr: Label 'Authorization failed to Azure function: %1', Locked = true; AzureFunctionCategoryLbl: Label 'Connect to Azure Functions', Locked = true; From b06b338cd5cf99d749096c164ac1b97e83ec916a Mon Sep 17 00:00:00 2001 From: waabsuea Date: Tue, 21 May 2024 12:51:21 +0200 Subject: [PATCH 4/4] Remove non debuggable --- .../App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al | 1 - 1 file changed, 1 deletion(-) diff --git a/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al b/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al index 1ccf629f62..0dc9f475cf 100644 --- a/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al +++ b/src/System Application/App/Azure Function/AzureFunctionsOAuth2Cert.Codeunit.al @@ -27,7 +27,6 @@ codeunit 7807 "Azure Functions OAuth2 Cert" implements "Azure Functions Authenti FailedToGetTokenErr: Label 'Authorization failed to Azure function: %1', Locked = true; AzureFunctionCategoryLbl: Label 'Connect to Azure Functions', Locked = true; - [NonDebuggable] procedure Authenticate(var RequestMessage: HttpRequestMessage): Boolean var Uri: Codeunit Uri;