Forum Discussion

dougb628's avatar
dougb628
Copper Contributor
Apr 26, 2019
Solved

SharePoint Authentication from C# Application

I've been struggling a bit to get authentication working. My C# application is a COM-based Add-In for a product called Enterprise Architect. In the app, we want to copy files to/from SharePoint, and to do that, I have to get a ClientContext object for the current user. I'm currently using AuthenticationManager.GetWebLoginClientContext(), but it has started behaving oddly - it has always popped up a browser window, but the window used to go away on its own once the authentication was done. Now that window is getting "stuck" and never closes unless I close it. This is my code:

 

using ODP = OfficeDevPnP.Core;

 

ODP.AuthenticationManager authManager = new ODP.AuthenticationManager();
ctx = authManager.GetWebLoginClientContext(ContextUrl);

 

If I close the browser window, ctx ends up being null.

 

I have also created a test harness console application that calls through to this same code, and when I run the console app, the browser form does in fact go away on its own, and the code works. But when I exercise this code via Enterprise Architect's COM-based Add-In interface, which  calls code that ends up going through this same exact code, the browser window does not close on its own as described above.

 

I have also considered switching over to AuthenticationManager.GetAzureADWebApplicationAuthenticatedContext(), but that would require a way of getting an access token. I have found lots of examples online, but they ALL refer to a MicrosoftGraphHelper class that has a GetAccessTokenForCurrentUser() method. For the life of me, I cannot find a NuGet package or anything that has an implementation of this MicrosoftGraphHelper class. For example:

 

using ODP = OfficeDevPnP.Core;

 

ODP.AuthenticationManager authManager = new ODP.AuthenticationManager();
ctx = authManager.GetAzureADWebApplicationAuthenticatedContext(ContextUrl, (url) => { return (MicrosoftGraphHelper.GetAccessTokenForCurrentUser(url)); });

 

I never would have expected this to be this hard to figure out - I have burned many hours, finding many false trails related to previous ways of interfacing with SharePoint, many of which are no longer recommended. For example, that OfficeDevPnP assembly import - it was quite a while before I found something that said that SharePointPnPCoreOnline is the currently recommended way of integrating to SharePoint, and other ways are not recommended because they are no longer being maintained.

 

Perhaps the best course of action would be for someone to recommend a good tutorial for basic integration from C# to SharePoint Online.

 

Help!

  • I have this working now, and the issue seems to have been related to the URL used when you get your client context object. Our SharePoint implementation has multiple levels of sites within it. We have separate sites for every customer, and then a top level site. I was attempting to get a file from a library under a customer site, and I had been using a URL that corresponded to the customer site. Once I changed the code to use the top level site (literally just the domain name) for the client context, the popup browser started getting the FedAuth cookie and things started working. So either I don't properly understand how our SharePoint is implemented, or the authentication method is extremely sensitive to the URL you use to get the cookies. The absolute URL to the file I was attempting to copy down looks something like this:

     

    https://mycompany.sharepoint.com/customers/theclientname/797%20Project%20Name/In%20Process%20Templates/standard.xml

     

    This URL is a valid site:

    https://mycompany.sharepoint.com/customers/theclientname

     

    But when I used that URL with AuthenticationManager.GetWebLoginClientContext(), it failed. Switching it to use:

    https://mycompany.sharepoint.com

    to get the client context fixed the problem. Now, if permissions were different at these different levels, I suspect this would have failed - it would have gotten a valid client context, but suspect I could still have gotten a permissions error when trying to use OpenBinaryStream() on my file object.

     

    This was a frustrating journey, and I was disappointed to not get any feedback from anyone else. Apparently my limited understanding of SharePoint and how to integrate to it is not as common as I thought it might be.

9 Replies

  • dougb628's avatar
    dougb628
    Copper Contributor

    I have this working now, and the issue seems to have been related to the URL used when you get your client context object. Our SharePoint implementation has multiple levels of sites within it. We have separate sites for every customer, and then a top level site. I was attempting to get a file from a library under a customer site, and I had been using a URL that corresponded to the customer site. Once I changed the code to use the top level site (literally just the domain name) for the client context, the popup browser started getting the FedAuth cookie and things started working. So either I don't properly understand how our SharePoint is implemented, or the authentication method is extremely sensitive to the URL you use to get the cookies. The absolute URL to the file I was attempting to copy down looks something like this:

     

    https://mycompany.sharepoint.com/customers/theclientname/797%20Project%20Name/In%20Process%20Templates/standard.xml

     

    This URL is a valid site:

    https://mycompany.sharepoint.com/customers/theclientname

     

    But when I used that URL with AuthenticationManager.GetWebLoginClientContext(), it failed. Switching it to use:

    https://mycompany.sharepoint.com

    to get the client context fixed the problem. Now, if permissions were different at these different levels, I suspect this would have failed - it would have gotten a valid client context, but suspect I could still have gotten a permissions error when trying to use OpenBinaryStream() on my file object.

     

    This was a frustrating journey, and I was disappointed to not get any feedback from anyone else. Apparently my limited understanding of SharePoint and how to integrate to it is not as common as I thought it might be.

    • kirstenray's avatar
      kirstenray
      Copper Contributor

      dougb628 I'm glad you continued to add comments here as I was having the same issues.  Someone reported this as a bug in December 2019, however it is not fixed yet, https://github.com/pnp/PnP-Sites-Core/issues/2508. 

       

      Though we all are seeing the same behavior, the underlying causes are different.  The reporter of the bug found the error when using a SharePoint Add in and his work around was to add another cookie to the list of cookies it attempted to find.  Your issue was that it wasn't providing a cookie that was in fact there.  My issue is that it freezes on the browser.Navigated call. I get pop-up browser window, but when debugging it never drops into the code under browser.Navigated.  I have no fix at the moment.  This behavior is intermittent, it will work once and then not work again until my app is closed and reopened.  No exception occur and even when I step into the browser.Navigated call, it actually looks like it just skips over the call and goes to the next line.

      • Oliver_Dracus's avatar
        Oliver_Dracus
        Copper Contributor

        kirstenray You not alone :(.

        In a meantime did you find something? I am currently debugging and like you said sometimes it works and sometimes not.

        Mainly, I noticed that if in main site where I am connected if I have subsites and try to drilldown in some of subsites that, usually, does not work.

  • dougb628's avatar
    dougb628
    Copper Contributor

    So I dug into this a little deeper, and discovered that it is happening because the code behind the GetWebLoginClientContext() method is looking at the cookies, specifically for cookies that have "FedAuth" or "EdgeAccessCookie" in their names. If those cookies are found, and only if they are found, the form automatically closes. I created my own implementation of the method so I could step through the code, and discovered that since it is not finding those cookies, it is not closing the form. So the real issue is that those cookies are not present in the HTTP Response. At least I've got a better lead now.

    • dougb628's avatar
      dougb628
      Copper Contributor

      More research results...

       

      Using Fiddler, I can see that the FedAuth cookie DOES come back in the response, but the part of GetWebLoginClientContext that retrieves the cookies is not seeing that cookie.

       

      Looking into how the cookie retrieval process works I see that the code that retrieves the cookies is using InternetGetCookieEx() implemented in wininet.dll. That function is returning a string that does NOT contain the FedAuth cookie.

       

      I'm not quite sure where to go with this next, unless there is a different way to retrieve the cookies.

  • dougb628's avatar
    dougb628
    Copper Contributor

    Here's the link to the stackoverflow post that talked about https://www.nuget.org/packages/SharePointPnPCoreOnline being the recommended way to integrate to SharePoint:

     

    https://stackoverflow.com/questions/52707476/authentication-to-sharepoint-online-with-csom

Resources