Udostępnij za pośrednictwem


SharePoint Online: Pass Credentials to Web Service passively

 

SharePoint Online or Office 365 relies on Claims authentication. This makes things a little challenging when you are trying to work with the Web Services exposed by SPO. When I was trying to consume web Services with Default Credentials passed, it started throwing me Access Denied (401).

After little research I was able to come up with numerous code samples which would make use of the ClaimClientContext.GetAuthenticatedCookies method.

This method works fine as long as you are using the Application in User Interactive mode. The reason being it uses the Web Browser in a Form and asks for credentials. It then retrieves the cookie from the browser which can be passed along with the Web Service Headers.

The sample for such code is here: Connecting to SharePoint Online Web Services

Now the Big Question

How do I pass the credentials in a Passive mode ? How to pass credentials from a non user interactive application ?

Well, it took a while for me to figure out that and finally got the answer. The answer is with the SharePointOnlineCredentials Class.

You can use the GetAuthenticationCookie method to get the Cookie. I will show how you can pass your credentials from the code later in this blog.

The return type for this cookie is not a FedAuth cookie and hence it cannot be directly passed along with the Web Service Request.

Hence we will rip the contents of the cookie and create a new FedAuth Cookie which we can pass along with the web service to authenticate against a SPO site.

The whole code to get the cookie and create a FedAuth cookie is below

 

  
 static void Main(string[] args)
         {            
             string targetSiteURL = @"https://<SPO Site URL>";
             var targetSite = new Uri(targetSiteURL);
  
             var login = "<SPO User Name>";
             var password = "<SPO User Password>";
             var securePassword = new SecureString();
  
             foreach (char c in password)
             {
                 securePassword.AppendChar(c);
             }
  
             SharePointOnlineCredentials onlineCredentials = new SharePointOnlineCredentials(login, securePassword);
             CallSPOServiceWithoutPopup(targetSite, onlineCredentials);            
  
         }
  
 private static void CallSPOServiceWithoutPopup(Uri targetSite, SharePointOnlineCredentials onlineCredentials)
         {
             //I had added the reference of the Lists Service - You can add any
             Lists list = new Lists();
             list.UseDefaultCredentials = false;
  
             string authCookieValue = onlineCredentials.GetAuthenticationCookie(targetSite);
             list.CookieContainer = new CookieContainer();
             list.CookieContainer.Add(
                 new Cookie("FedAuth",
                 authCookieValue.TrimStart("SPOIDCRL=".ToCharArray()),//This is to remove the prefix from the cookie's value
                 String.Empty,
                 targetSite.Authority));
  
             list.Url = @"<Web Service URL>";
  
             string listName = "Shared Documents";
             string rowLimit = "5";
  
             // Instantiate an XmlDocument object 
             System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
             System.Xml.XmlElement query = xmlDoc.CreateElement("Query");
             System.Xml.XmlElement viewFields = xmlDoc.CreateElement("ViewFields");
             System.Xml.XmlElement queryOptions = xmlDoc.CreateElement("QueryOptions");
  
             //*Use CAML query*/ 
             query.InnerXml = "<Where><Gt><FieldRef Name=\"ID\" />" + 
                 "<Value Type=\"Counter\">0</Value></Gt></Where>";
             viewFields.InnerXml = "<FieldRef Name=\"Title\" />";
             //queryOptions.InnerXml = "";
             queryOptions.InnerXml = 
                 "<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>" + 
                 "<DateInUtc>TRUE</DateInUtc>";
             System.Xml.XmlNode nodes = 
                 list.GetListItems(
                     listName, 
                     viewName, 
                     query, 
                     viewFields, 
                     rowLimit, 
                     null, 
                     string.Empty);
             string ixml = list.GetList(listName).InnerXml;
             Console.WriteLine(
                 "Retrieving title of all the items in SharePoint Online" +
                  "sites 'Shared Documents' using Lists webservice");
             Console.WriteLine(
                 "===========================================" +
                 "=============================================");
             foreach (System.Xml.XmlNode node in nodes)
             {
                 if (node.Name == "rs:data")
                 {
                     for (int i = 0; i < node.ChildNodes.Count; i++)
                     {
                         if (node.ChildNodes[i].Name == "z:row")
                         {
                             Console.WriteLine(
                                 node.ChildNodes[i].Attributes["ows_Title"].Value);
                         }
                     }
                 }
             }
             Console.ReadLine();            
         }

 

With the above sample you can call the SPO web Services in unattended mode (in Scheduled jobs or any application that would not run in non User Interaction mode).

 

Hope this sample helps!!

Comments

  • Anonymous
    June 05, 2014
    This was exactly what I was looking for.  It felt like I was looking for days for a passive solution.  It works!  Thanks!

  • Anonymous
    July 28, 2014
    I'm getting a null value for authentication cookiestring authCookieValue = onlineCredentials.GetAuthenticationCookie(targetSite);Could you please help me in this.

  • Anonymous
    February 10, 2015
    due to a recent security change in SPO, the name of the cookie should be IDCRL. Try this code when adding the cookie to cookie container:           list.CookieContainer.Add(                new Cookie("SPOIDCRL",                authCookieValue.TrimStart("SPOIDCRL=".ToCharArray()),//This is to remove the prefix from the cookie's value                String.Empty,                targetSite.Authority));

  • Anonymous
    February 11, 2015
    I am very new to SharePoint, and have been tasked with writing a web service that will use REST to access data in a SharePoint 365 tenant.   I got stuck in the above sample when it said to:          //I had added the reference of the Lists Service - You can add any           Lists list = new Lists();How do I add the lists service to VS2013?  Any pointers in how to connect to the REST APIs would be gratefully received as well

  • Anonymous
    March 10, 2015
    I am getting access denied for the below methodonline_listservice.GetListCollection()Server was unable to process request. ---> Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))"}I am using the same above FED auth cookie method but throwing the above errorIt is working fine with sharepoint 2007 but for SharePoint Online 2013 its throwing above error.Please help!!!

  • Anonymous
    June 18, 2015
    @Sean Flanagan: This really helped me.  Thanks a tonne.

  • Anonymous
    October 01, 2015
    This post and Sean Flanagan's comment saved me from hours of heartache.  Bless you both.

  • Anonymous
    May 03, 2016
    It helped me ... Thanks a lot :)