4
votes

I have a test environment set up using windows server 2012 R2, ADFS and sharepoint 2013. I can successfully login to Sharepoint 2013 using ADFS as the Claims Identity provider. Now I am trying to login to Sharepoint from my C# application.

I am able to request the saml assertion token from adfs using the following.

Now i would like help with posting the saml token to SharePoint and retrieve a FedAuth cookie so I can passively login to SharePoint 2013 and upload a document from a C# application.

When I call the last method PostSharePointSTS() No Cookies are set.

most of the code has been the help of Leandro Boffi

[TestMethod]
public void GetSamlTestMethod()
{
  var client = new WebClient();

  client.Headers.Add("Content-Type", "application/soap+xml; charset=utf-8");
  string username = "[email protected]";
  string password = "Password1";
  string adfsServer = "https://logon.2012r2.local/adfs/services/trust/2005/UsernameMixed";
  string sharepoint = "https://portal.2012r2.local/_trust/";
  var samlRequest = GetSAML()
    .Replace("[Username]", username)
    .Replace("[Password]", password)
    .Replace("[To]", adfsServer)
    .Replace("[applyTo]", sharepoint);

  var result = client.UploadString(
          address: "https://logon.2012r2.local/adfs/services/trust/2005/UsernameMixed",
          method: "POST",
          data: samlRequest);

          PostSharePointSTS( GetSAMLAssertion(result) );

}
private static string GetSAMLAssertion(string response)
{

  XDocument samlResponse = XDocument.Parse( response);

  // Check response xml for faults/errors
  if(samlResponse.Root == null)
    throw new ApplicationException("Invalid response received from authentication service.");

  XNamespace s = "http://www.w3.org/2003/05/soap-envelope";
  XNamespace psf = "http://schemas.microsoft.com/Passport/SoapServices/SOAPFault";
  XNamespace wst = "http://schemas.xmlsoap.org/ws/2005/02/trust"; // "http://docs.oasis-open.org/ws-sx/ws-trust/200512";// 
  XNamespace wsp = "http://schemas.xmlsoap.org/ws/2004/09/policy";
  XNamespace wsa = "http://www.w3.org/2005/08/addressing";
  XNamespace wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
  const string saml = "urn:oasis:names:tc:SAML:1.0:assertion";

  // the logon token is in the SAML assertion element of the message body
  XDocument xDoc = XDocument.Parse(response, LoadOptions.PreserveWhitespace);
  var assertion = from e in xDoc.Descendants()
                  where e.Name == XName.Get("Assertion", saml)
                  select e;

 string samlAssertion = assertion.FirstOrDefault().ToString();     

  // for some reason the assertion string needs to be loaded into an XDocument
  // and written out for for the XML to be valid. Otherwise we get an invalid
  // XML error back from ADFSs
  XDocument doc1 = XDocument.Parse(samlAssertion);
  samlAssertion = doc1.ToString(SaveOptions.DisableFormatting);
  return samlAssertion;

}



   private static string GetSAML()
    {
      const string saml = @"<?xml version='1.0' encoding='utf-8' ?>

<s:Envelope xmlns:s='http://www.w3.org/2003/05/soap-envelope' xmlns:a='http://www.w3.org/2005/08/addressing' xmlns:u='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>
    <s:Header>
        <a:Action s:mustUnderstand='1'>http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
        <a:ReplyTo>
            <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
        </a:ReplyTo>
        <a:To s:mustUnderstand='1'>[To]</a:To>
        <o:Security s:mustUnderstand='1' xmlns:o='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'>
            <o:UsernameToken>
                <o:Username>[Username]</o:Username>
                <o:Password>[Password]</o:Password>
            </o:UsernameToken>
        </o:Security>
    </s:Header>
    <s:Body>
        <t:RequestSecurityToken xmlns:t='http://schemas.xmlsoap.org/ws/2005/02/trust'>
            <wsp:AppliesTo xmlns:wsp='http://schemas.xmlsoap.org/ws/2004/09/policy'>
                <a:EndpointReference>
                    <a:Address>[applyTo]</a:Address>
                </a:EndpointReference>
            </wsp:AppliesTo>
            <t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
            <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
            <t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
        </t:RequestSecurityToken>
    </s:Body>
</s:Envelope>";
      return saml;
    }
private static void PostSharePointSTS(string assertion)
{

  // Submit the BinarySecurityToken to SPO and retrieve response
 var loginUri = new Uri("https://logon.2012r2.local/adfs/ls?wa=wsignin1.0&wtrealm=urn:sharepoint:portal");
  var requestCookies = new CookieContainer();

  var request = (HttpWebRequest)WebRequest.Create(loginUri);
  request.AllowAutoRedirect = false;
  request.ContentType = "application/x-www-form-urlencoded";
  request.ContentLength = assertion.Length;
  request.CookieContainer = requestCookies;
  request.Method = "POST";
  request.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)";

  using(var requestWriter = new StreamWriter(request.GetRequestStream()))
  {
    requestWriter.Write(assertion);
    requestWriter.Close();
  }

  var response = (HttpWebResponse)request.GetResponse();
  switch(response.StatusCode)
  {
    case HttpStatusCode.OK:
    case HttpStatusCode.Found:
    break;

    // TODO: Log error?
    //default:
    //return false;
  }

}

When I try to Post the given SAML token to SharePOint I get the following. But no cookies are set.

HTTP/1.1 302 Found
Content-Length: 0
Content-Type: text/html; charset=utf-8
Location: https://logon.2012r2.local:443/adfs/ls/wia?wa=wsignin1.0&wtrealm=urn:sharepoint:portal
Server: Microsoft-HTTPAPI/2.0
Date: Sat, 16 Aug 2014 10:55:51 GMT

    This response did not set any cookies.
This response did not contain a P3P Header.

Validate P3P Policies at: http://www.w3.org/P3P/validator.html
Learn more at: http://fiddler2.com/r/?p3pinfo
1
Did you ever find a solution for this issue?joweiser

1 Answers

0
votes

Why don't you just use the standard SharePoint CSOM library to do whatever you want in SharePoint? CSOM does all the necessary ADFS interaction on behalf of the user on the SharePoint side automatically.