14

I followed the following document to create a x509 certificate with the Azure AD App Registration.

https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread

I generated the .pfx file, set the password, and I also registered the app in my tenant Azure AD, and then updated the manifest with the keycredentials section.

Then, I am creating a WEB API that receives some parameters, including the .pfx file.

 [HttpPut]
        public async Task<IHttpActionResult> PutTenant([ModelBinder(typeof(TenantModelBinder))] Tenant tenant)
        {
            try
            {               
                var cert = new X509Certificate2(tenant.CertificateFile, tenant.CertificatePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);

                using (var cc = new OfficeDevPnP.Core.AuthenticationManager().GetAzureADAppOnlyAuthenticatedContext(tenant.SiteCollectionTestUrl, tenant.ApplicationId, tenant.TenantDomainUrl, cert))
                {
                    cc.Load(cc.Web, p => p.Title);
                    cc.ExecuteQuery();
                };
            }
            catch (System.Exception)
            {
                return BadRequest("Configuration Invalid");
            }

I am using the bytearray coming from the HttpRequest to create the x509 object.

However I get this error:

Message "Method not found: 'Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.AcquireToken(System.String, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate)'."   string

Stacktrace:

at OfficeDevPnP.Core.AuthenticationManager.<>c__DisplayClass36_0.<GetAzureADAppOnlyAuthenticatedContext>b__0(Object sender, WebRequestEventArgs args)\r\n   at Microsoft.SharePoint.Client.ClientRuntimeContext.OnExecutingWebRequest(WebRequestEventArgs args)\r\n   at Microsoft.SharePoint.Client.ClientContext.GetWebRequestExecutor()\r\n   at Microsoft.SharePoint.Client.ClientContext.GetFormDigestInfoPrivate()\r\n   at Microsoft.SharePoint.Client.ClientContext.EnsureFormDigest()\r\n   at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()\r\n   at TenantManagementWebApi.Controllers.TenantController.<PutTenant>d__2.MoveNext() in C:\\Users\\levm3\\source\\repos\\TenantManagementWebApi\\Controllers\\TenantController.cs

The error is thrown in the executequery

really clueless here.

Update:

I noticed this in my web.config

 <dependentAssembly>
        <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
        <bindingRedirect oldVersion="0.0.0.0-3.19.5.13701" newVersion="3.19.5.13701"/>
      </dependentAssembly>

and this on my packages.config

  <package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="3.19.5" targetFramework="net461" />
Luis Valencia
  • 32,619
  • 93
  • 286
  • 506
  • 2
    When an end user consent to a multi-tenant application, a representation of that application (a service principal) is created in the user's tenant. If the application is multi-tiered (i.e. it uses another application, an API) you can use knownClientApplications to tell AAD to register that service principal too. Please see details here https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-devhowto-multi-tenant-overview. So, do these automatic registrations cover your use case ("My final goal is to be able to create an Azure AD App registration programatically")? – andresm53 Jul 10 '18 at 16:46
  • 1
    Luis. ADAL.NET is multi-target. can you please check in the csproj the platform was used - look at the hint path of Microsoft.IdentityModel.Clients.ActiveDirector (it should be net45, and not another platform under packages). The reason I propose that, is that we have sometimes seen NuGet package manager pickup the wrong platform in the case of multi-targets nuget package. Finally were can I see information about OfficeDevPnP.Core.AuthenticationManager ? maybe it uses ADAL v2.0 (which would not be compatible with ADAL v3.x) – Jean-Marc Prieur Jul 29 '18 at 02:03
  • Hello Jean, thanks for your help, OfficeDevPnp core component is here: https://github.com/SharePoint/PnP-Sites-Core/tree/master/Core/OfficeDevPnP.Core, and on my project I also have this: my project is .net 4.6.1, about platform it says AnyCPU – Luis Valencia Jul 29 '18 at 07:59
  • I think I know what the problem is, but I have no idea how to fix it, Fist basically my asp.net webapi is protected with Azure AD, by using the standard startup.auth.cs mechanism: https://www.screencast.com/t/EvJ7bIu8b, so my project references that assembly, Second, I use the office PnP nuget package to make Sharepoint Operations, as in the first link explained above, with AppOnly policy I can use the office pnp to execute any sharepoint operations. So there is a dll conflict here which I am not sure how to fix. – Luis Valencia Jul 29 '18 at 19:31
  • @Jean-MarcPrieur with my last commend in mind, what would the best way to fix this? I was thinking that maybe instead of downloading the nugetpackage, I can manually download the office pnp core package and update the referenced AD dll? – Luis Valencia Jul 30 '18 at 10:53
  • @luisValencia I agree with the answer below – Jean-Marc Prieur Jul 31 '18 at 14:29

1 Answers1

5

PnP Core currently uses the older version, 2.29.0, of the Microsoft.IdentityModel.Clients.ActiveDirectory package.

Best would be that you downgrade the version used in your API project to the one used by PnP Framework which will work for sure.

Related to the error, the framework is calling the AuthenticationContext.AcquireToken method internally which has been deprecated in the newer Nuget v3 package.

So, it looks like the PnP code is calling this method belongs to the v2 version while the correct method of v3 package to use is AcquireTokenAsync of the v3 version which is resulting in the conflict.

Reference - OfficeDevPnP Core package.config file

Now , we can see that the is already a PR in place to update the nuget package in the PnP Framework itself, which when accepted will solve your issue right away. But might take some to get accepted, so dont hold your breath :)

AuthenticationResult.AcquireToken deprecated in ADAL 3.x and how to fix.

Microsoft Docs - AuthenticationContext.AcquireTokenAsync Method

So best would be that you either downgrade your API project to v2 or wait for the PnP Framework to upgrade the package and its necessary dependencies.

Another option, if you are only using PnP to authenticate, then you can use the below helper method which wont require you to change the package. But if you using other functionality like provisioning or other extensions, then you need to downgrade it unfortunately. This is modified from what is used internally in PnP itself to make use of the v3 package changes :

public ClientContext GetAzureADAppOnlyAuthenticatedContext(string siteUrl, string clientId, string tenant, X509Certificate2 certificate)
{
    var clientContext = new ClientContext(siteUrl);

    string authority = string.Format(CultureInfo.InvariantCulture, "https://login.windows.net/{0}/", tenant);

    var authContext = new AuthenticationContext(authority);

    var clientAssertionCertificate = new ClientAssertionCertificate(clientId, certificate);

    var host = new Uri(siteUrl);

    clientContext.ExecutingWebRequest += (sender, args) =>
    {
        var ar = authContext.AcquireTokenAsync(host.Scheme + "://" + host.Host + "/", clientAssertionCertificate).GetAwaiter().GetResult();
        args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + ar.AccessToken;
    };

    return clientContext;
}
Gautam Sheth
  • 2,442
  • 1
  • 17
  • 16
  • Thanks Gautam, I downgraded and I dont have that error anymore, however in the GetAzureADAppOnlyAuthenticatedContext method it stays a lot of time, and then on my react app I get a Failed to Fetch Error, I am not sure if its timeout or something, it takes like 2 minutes before the error is thrown. However you answer is very detailed, thanks for that. – Luis Valencia Jul 31 '18 at 17:08
  • Cheers, happy to help :) , regarding the time taken, can you try this code in sample console and check ? Also, if you have time, can also check with above sample code using v3 Nuget package in console app. Probably, we might find something. – Gautam Sheth Jul 31 '18 at 17:23