skip to Main Content

I have an Azure Function which uses PnP.Core.Services to interact with SharePoint to create a list item. The Azure function is based on .net version 6.0.

I have this startup.cs:-

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using PnP.Core.Auth;
using System.Security.Cryptography.X509Certificates;

[assembly: FunctionsStartup(typeof(FunctionApp2.Startup))]
namespace FunctionApp2
{
    class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {

            var config = builder.GetContext().Configuration;
            var azureFunctionSettings = new AzureFunctionSettings();
            config.Bind(azureFunctionSettings);
            builder.Services.AddPnPCore(options =>
            {
                options.DisableTelemetry = true;
                var authProvider = new X509CertificateAuthenticationProvider(azureFunctionSettings.ClientId,
                    azureFunctionSettings.TenantId,
                    StoreName.My,
                    StoreLocation.CurrentUser,
                    azureFunctionSettings.CertificateThumbprint);
                options.DefaultAuthenticationProvider = authProvider;

                options.Sites.Add("Default", new PnP.Core.Services.Builder.Configuration.PnPCoreSiteOptions

                {
                    SiteUrl = azureFunctionSettings.SiteUrl,
                    AuthenticationProvider = authProvider


                });

            });

        }

    }
}

and this Function1.cs:-

using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
using PnP.Core.Services;
using PnP.Core.Model.SharePoint;
using System.Collections.Generic;

namespace FunctionApp2
{
    public class Function1

    {
        private readonly IPnPContextFactory pnpContextFactory;
        public Function1(IPnPContextFactory pnpContextFactory)
        {
            this.pnpContextFactory = pnpContextFactory;

        }
        [FunctionName("Function1")]
        public void Run([TimerTrigger("0 */5 * * * *")] TimerInfo myTimer, ILogger log)
        {
            log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

            using (var context = pnpContextFactory.Create("Default"))
            {
                var myList = context.Web.Lists.GetByTitle("SubFolders");
                Dictionary<string, object> values = new Dictionary<string, object>
    {
        { "Title", System.DateTime.Now }
    };

                // Use the AddBatch method to add the request to the current batch
                myList.Items.AddBatch(values);
                context.Execute();
            }
        }
    }
}

and this AzureFunctionSettings.cs:-

using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace FunctionApp2
{
    internal class AzureFunctionSettings
    {
        public string SiteUrl { get; set; }
        public string TenantId { get; set; }
        public string ClientId { get; set; }
        public StoreName CertificateStoreName { get; set; }
        public StoreLocation CertificateStoreLocation { get; set; }
        public string CertificateThumbprint { get; set; }


    }
}

now i am working with a client and they do not allow us to use any open source technologies like PnP. so what i need to do to replace my above PnP code with CSOM code? and is there a CSOM code for .net 6?

Thanks

2

Answers


  1. You can use Microsoft.Identity.Client instead of PnP. I have never used the certificate flow myself but something like this should work:

      using Microsoft.Identity.Client;
      using Microsoft.SharePoint.Client;
      
      // ...
      // step 1: Acquire bearer token
      X509Certificate2 certificate = LoadCertificate(StoreName.My, StoreLocation.CurrentUser,azureFunctionSettings.CertificateThumbprint);
    
      IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create("your_client_id")
                .WithCertificate(certificate)
                .WithAuthority(new Uri("https://login.microsoftonline.com/your_tenant_id/"))
                .Build();
    
    
      AuthenticationResult result = await app.AcquireTokenForClient(new[] { $"https://yourSharePoint.sharepoint.com/.default" }).ExecuteAsync();
    
      // step 2: Use bearer token with Microsoft.SharePoint.Client.ClientContext to access Sharepoint
    
      ClientContext ctx = new ClientContext("https://yourSharePoint.sharepoint.com/");
            
      ctx.ExecutingWebRequest += (s, e) =>
      {
         e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + result.AccessToken;
      };
    
      //do your thing with ctx.Web.Lists etc.
    

    The code to load your certificate from the store as in the PnP source

    public static X509Certificate2 LoadCertificate(StoreName storeName, StoreLocation storeLocation, string thumbprint)
        {
            // The following code gets the cert from the keystore
            X509Store store = new X509Store(storeName, storeLocation);
            store.Open(OpenFlags.ReadOnly);
    
            X509Certificate2Collection certCollection =
                    store.Certificates.Find(X509FindType.FindByThumbprint,
                    thumbprint, false);
    
            X509Certificate2Enumerator enumerator = certCollection.GetEnumerator();
    
            X509Certificate2 cert = null;
    
            while (enumerator.MoveNext())
            {
                cert = enumerator.Current;
            }
    
            return cert;
        }
    
    Login or Signup to reply.
  2. If you want to use CSOM and authenticate with a certificate then you need to associate the certificate with your application in Azure. I assume that you have already generated the certificate and your application is registered in Azure Portal.

    Open your app in Azure Portal and click on Manage -> Certificates & secrets.

    enter image description here

    On tab Certificates click on Upload certificate and upload certificate from cer file.

    enter image description here

    Now you need to create a new Key vaults resource in Azure portal

    enter image description here

    Remember your Vault URI of your Key vault resource enter image description here

    Click on Objects -> Certificates and then on Generate/Import button to import the certificate from pfx file. Remember the name of the certificate.

    enter image description here

    In the code you need to add Azure.Identity, Azure.Security.KeyVault.Certificate and Microsoft.Identity.Client nuget packages.

    Create CertificateClient to download the certificate from Key vault and use the certificate in ConfidentialClientApplicationBuilder.

    var certClient = new CertificateClient(new 
    Uri("https://<your_vault_uri>.vault.azure.net/"), new DefaultAzureCredential());
    
    // download the certificate based on the name
    var cert = certClient.DownloadCertificate("MyTestCertificate");
    
    // use the certificate in ConfidentialClientApplicationBuilder
    
    var confClientApp = ConfidentialClientApplicationBuilder.Create("<client_id>")
                .WithCertificate(cert)
                .WithAuthority(new Uri("https://login.microsoftonline.com/<tenant_id>/v2.0/"))
                .Build();
    
    AuthenticationResult result = await confClientApp.AcquireTokenForClient(new[] { $"https://<tenant_name>.sharepoint.com/.default" })
                   .ExecuteAsync();
    var token = result.AccessToken;
    
    // use the token to authenticate the request from CSOM 
    var context = new ClientContext(new Uri("<your_web_url>");
        
    context.ExecutingWebRequest += (s, e) =>
    {
       e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + token;
    };
    
    // your code
    ...
    

    Probably you will need to learn more about DefaultAzureCredentail to configure it for using in production. DefaultAzureCredential tries different credential types.
    For development you can choose an account for your apps to authenticate and access Azure resources in Visual Studio -> Tools -> Options -> Azure Service Authentication.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search