Skip to content

Commit

Permalink
Client Credentials Support for Sharepoint (#705)
Browse files Browse the repository at this point in the history
#### Summary
Add Client Credentials Support for Sharepoint

#### Work Item(s)
Fixes #524 

Fixes
[AB#457003](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/457003)

---------

Co-authored-by: Darrick <[email protected]>
  • Loading branch information
2 people authored and JesperSchulz committed Mar 27, 2024
1 parent c7ee5db commit 344443e
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ codeunit 9142 "SharePoint Auth."
/// <param name="ClientId">The Application (client) ID that the Azure portal - App registrations experience assigned to your app.</param>
/// <param name="ClientSecret">The Application (client) secret configured in the "Azure Portal - Certificates &amp; Secrets".</param>
/// <param name="Scope">A scope that you want the user to consent to.</param>
/// <returns>Codeunit instance implementing authorization interface</returns>
/// <returns>Codeunit instance implementing authorization interface</returns>
procedure CreateAuthorizationCode(EntraTenantId: Text; ClientId: Text; ClientSecret: SecretText; Scope: Text): Interface "SharePoint Authorization";
var
Scopes: List of [Text];
Expand All @@ -82,4 +82,37 @@ codeunit 9142 "SharePoint Auth."
begin
exit(SharePointAuthImpl.CreateAuthorizationCode(EntraTenantId, ClientId, ClientSecret, Scopes));
end;

/// <summary>
/// Creates an authorization mechanism with the Client Credentials Grant Flow.
/// </summary>
/// <param name="AadTenantId">Azure Active Directory tenant ID</param>
/// <param name="ClientId">The Application (client) ID that the Azure portal - App registrations experience assigned to your app.</param>
/// <param name="Certificate">The Base64-encoded certificate for the Application (client) configured in the Azure Portal - Certificates &amp; Secrets.</param>
/// <param name="CertificatePassword">Password for the certificate.</param>
/// <param name="Scope">A scope that you want the user to consent to.</param>
/// <returns>Codeunit instance implementing authorization interface</returns>
procedure CreateClientCredentials(AadTenantId: Text; ClientId: Text; Certificate: SecretText; CertificatePassword: SecretText; Scope: Text): Interface "SharePoint Authorization";
var
Scopes: List of [Text];
begin
Scopes.Add(Scope);
exit(CreateClientCredentials(AadTenantId, ClientId, Certificate, CertificatePassword, Scopes));
end;

/// <summary>
/// Creates an authorization mechanism with the Client Credentials Grant Flow.
/// </summary>
/// <param name="AadTenantId">Azure Active Directory tenant ID</param>
/// <param name="ClientId">The Application (client) ID that the Azure portal - App registrations experience assigned to your app.</param>
/// <param name="Certificate">The Base64-encoded certificate for the Application (client) configured in the Azure Portal - Certificates &amp; Secrets.</param>
/// <param name="CertificatePassword">Password for the certificate.</param>
/// <param name="Scopes">A list of scopes that you want the user to consent to.</param>
/// <returns>Codeunit instance implementing authorization interface</returns>
procedure CreateClientCredentials(AadTenantId: Text; ClientId: Text; Certificate: SecretText; CertificatePassword: SecretText; Scopes: List of [Text]): Interface "SharePoint Authorization";
var
SharePointAuthImpl: Codeunit "SharePoint Auth. - Impl.";
begin
exit(SharePointAuthImpl.CreateClientCredentials(AadTenantId, ClientId, Certificate, CertificatePassword, Scopes));
end;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@ codeunit 9143 "SharePoint Auth. - Impl."
InherentEntitlements = X;
InherentPermissions = X;

[NonDebuggable]
procedure CreateAuthorizationCode(EntraTenantId: Text; ClientId: Text; ClientSecret: SecretText; Scopes: List of [Text]): Interface "SharePoint Authorization";
var
SharePointAuthorizationCode: Codeunit "SharePoint Authorization Code";
begin
SharePointAuthorizationCode.SetParameters(EntraTenantId, ClientId, ClientSecret, Scopes);
exit(SharePointAuthorizationCode);
end;

procedure CreateClientCredentials(AadTenantId: Text; ClientId: Text; Certificate: SecretText; CertificatePassword: SecretText; Scopes: List of [Text]): Interface "SharePoint Authorization";
var
SharePointClientCredentials: Codeunit "SharePoint Client Credentials";
begin
SharePointClientCredentials.SetParameters(AadTenantId, ClientId, Certificate, CertificatePassword, Scopes);
exit(SharePointClientCredentials);
end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace System.Integration.Sharepoint;

codeunit 9145 "SharePoint Client Credentials" implements "SharePoint Authorization"
{
Access = Internal;
InherentEntitlements = X;
InherentPermissions = X;

var
ClientId: Text;
Certificate: SecretText;

AadTenantId: Text;
Scopes: List of [Text];
CertificatePassword: SecretText;

procedure SetParameters(NewAadTenantId: Text; NewClientId: Text; NewCertificate: SecretText; NewCertificatePassword: SecretText; NewScopes: List of [Text])

begin
AadTenantId := NewAadTenantId;
ClientId := NewClientId;
Certificate := NewCertificate;
CertificatePassword := NewCertificatePassword;
Scopes := NewScopes;
end;

procedure Authorize(var HttpRequestMessage: HttpRequestMessage);
var
Headers: HttpHeaders;
BearerTxt: Label 'Bearer %1', Comment = '%1 = Token', Locked = true;
begin
HttpRequestMessage.GetHeaders(Headers);
Headers.Add('Authorization', SecretStrSubstNo(BearerTxt, GetToken()));
end;

local procedure GetToken(): SecretText
var
ErrorText: Text;
AccessToken: SecretText;
begin
if not AcquireToken(AccessToken, ErrorText) then
Error(ErrorText);
exit(AccessToken);
end;

local procedure AcquireToken(var AccessToken: SecretText; var ErrorText: Text): Boolean
var
OAuth2: Codeunit System.Security.Authentication.OAuth2;
FailedErr: Label 'Failed to retrieve an access token.';
ClientCredentialsTokenAuthorityUrlTxt: Label 'https://login.microsoftonline.com/%1/oauth2/v2.0/token', Comment = '%1 = AAD tenant ID', Locked = true;
IsSuccess: Boolean;
AuthorityUrl: Text;
IdToken: Text;
begin
AuthorityUrl := StrSubstNo(ClientCredentialsTokenAuthorityUrlTxt, AadTenantId);
ClearLastError();
if (not OAuth2.AcquireTokensFromCacheWithCertificate(ClientId, Certificate, CertificatePassword, '', AuthorityUrl, Scopes, AccessToken, IdToken)) or (AccessToken.IsEmpty()) then
OAuth2.AcquireTokensWithCertificate(ClientId, Certificate, CertificatePassword, '', AuthorityUrl, Scopes, AccessToken, IdToken);

IsSuccess := not AccessToken.IsEmpty();

if not IsSuccess then begin
ErrorText := GetLastErrorText();
if ErrorText = '' then
ErrorText := FailedErr;
end;

exit(IsSuccess);
end;
}

0 comments on commit 344443e

Please sign in to comment.