Showing posts with label Claims. Show all posts
Showing posts with label Claims. Show all posts

Tuesday, January 31, 2012

Programmatic SiteMinder 2.0 authentication and getting the FedAuth cookie to access SharePoint 2010 service

-->
One of our client upgraded their SSO authentication mechanism for their site from SiteMinder v1 to SiteMinder v2. We have built one project for this client that was making use of SSO to authenticate users and allowing them access. With WSS 3.0 and SiteMinder v1, we didn’t had much issues. We passed the username password, got hold of the SAML token and used it in the cookie container to consume the service from WSS 3.0.

But with sharepoint 2010 (claims enabled) and SiteMinder v2.0, there were a lot of difference. There were around 7-8 redirects before we hit the login page. Then we constructed the data to be posted and posted to the login page. Got the SAML token but it’s not finished yet. There were again a series of redirects before we hit the _Trust link. The trust link is where we post the web context, web result and web authentication data. Successfully posting these 3 data along with required cookies helped to get hold of the much wanted FedAuth cookie. This is the cookie that will help you consume services hosted at sharepoint 2010. Below is the full listing of the code.

public static void UpdateListItem(string listPath, string username, string password)
        {
            CookieContainer cookies = new CookieContainer();
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
            string message = string.Empty;

            try
            {

                // Open connection to Protected URI.  This will be intercepted and redirected
                // to SiteMinder login screen.
                Uri listUri = new Uri(listPath);
                HttpWebRequest request = WebRequest.Create(listUri) as HttpWebRequest;
                request.AllowAutoRedirect = false;

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                string url = string.Empty;
                string domain = listUri.Host; //"https://yourdomain.com";
                string userAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"; //very important to set the agent parameter to requests
                Cookie jcookie = null;

                while (response.StatusCode == HttpStatusCode.Redirect)
                {
                    url = response.Headers[HttpResponseHeader.Location];

                    //check headers for Set-Cookie
                    if (!string.IsNullOrEmpty(response.Headers[HttpResponseHeader.SetCookie]))
                    {
                        string[] cookie = response.Headers[HttpResponseHeader.SetCookie].Split(';');

                        string[] cookieNameValue = cookie[0].Split('=');
                        jcookie = new Cookie(cookieNameValue[0], cookieNameValue[1]);
                        jcookie.Domain = listUri.Host;

                        string[] cookiePathValue = cookie[1].Split('=');
                        jcookie.Path = cookiePathValue[1];

                        string cookieIsSecure = cookie[2];
                        if (cookieIsSecure.Trim().ToLower() == "secure")
                            jcookie.Secure = true;

                        cookies.Add(jcookie); // This is one of the cookie that is required when posting data to trust link. Verified using fiddler
                    }

                    request = WebRequest.Create(url) as HttpWebRequest;
                    request.AllowAutoRedirect = false;
                    request.UserAgent = userAgent;

                    response = (HttpWebResponse)request.GetResponse();
                }

                // Create the form data to post back to the server
                NameValueCollection namevalues = GetHTMLInputTags(ResponseToString(response));
                string postData = string.Empty;
                foreach (string key in namevalues.Keys)
                {
                    postData += key + "=" + System.Web.HttpUtility.UrlEncode(namevalues[key]) + "&";
                }
                postData += "postpreservationdata=&";
                postData += "userid=" + System.Web.HttpUtility.UrlDecode(username) + "&";
                postData += "password=" + System.Web.HttpUtility.UrlEncode(password);

                // Submit the data back to SiteMinder
                cookies.Add(response.Cookies);

                request = WebRequest.Create(url) as HttpWebRequest;
                request.CookieContainer = cookies;
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = postData.Length;
                request.Method = "POST";
                // Important: we need to handle the redirect ourselves
                request.AllowAutoRedirect = false;

                // post the data to the request
                using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
                {
                    sw.Write(postData); sw.Flush(); sw.Close();
                }

                // Important to get the cookies here (they will include the SMSESSION cookie)
                response = (HttpWebResponse)request.GetResponse();
                cookies.Add(response.Cookies);

                while (response.StatusCode == HttpStatusCode.Redirect)
                {

                    url = response.Headers[HttpResponseHeader.Location];

                    request = WebRequest.Create(url) as HttpWebRequest;
                    request.CookieContainer = cookies;
                    request.AllowAutoRedirect = false;

                    response = (HttpWebResponse)request.GetResponse();
                    cookies.Add(response.Cookies);

                }

                #region Manual Authenticate

                string rootUrl = string.Format("{0}://{1}", listUri.Scheme, listUri.Host);// "https://mydomain.com";
                request = WebRequest.Create(rootUrl) as HttpWebRequest;
                request.CookieContainer = cookies;
                request.AllowAutoRedirect = false;
                request.UserAgent = userAgent;
                response = (HttpWebResponse)request.GetResponse();
                cookies.Add(response.Cookies);

                while (response.StatusCode == HttpStatusCode.Redirect)
                {

                    url = response.Headers[HttpResponseHeader.Location];

                    if (url.StartsWith("/"))
                        url = rootUrl + url;

                    if (url.Contains("affwebservices"))
                        cookies.Add(jcookie); // This is the place we add the jsession cookie (seems optional)

                    request = WebRequest.Create(url) as HttpWebRequest;
                    request.CookieContainer = cookies;
                    request.UserAgent = userAgent;
                    request.AllowAutoRedirect = false;

                    response = (HttpWebResponse)request.GetResponse();
                    cookies.Add(response.Cookies);

                }
  
                #region Manual STS Post to Trust

                url = rootUrl + "/_trust/default.aspx";

                namevalues = GetHTMLInputTags(ResponseToString(response));

                string stringData = String.Format("wctx={0}&wresult={1}&wa=wsignin1.0",
                System.Web.HttpUtility.UrlEncode(namevalues["Wctx"]),
                System.Web.HttpUtility.UrlEncode(namevalues["wresult"].Replace(""", @"""")));

                request = HttpWebRequest.Create(url) as HttpWebRequest;

                Console.WriteLine(string.Format("Programmatic Post to URL = {0}
"
, request.RequestUri));
                Console.WriteLine(string.Format("Post Data = {0}

"
, stringData));

                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                request.CookieContainer = cookies;
                request.UserAgent = userAgent;
                request.AllowAutoRedirect = false; // This is important
                Stream newStream = request.GetRequestStream();

                // Actually send the request
                using (StreamWriter sw = new StreamWriter(newStream))
                {
                    sw.Write(stringData); sw.Flush(); sw.Close();
                }

                response = request.GetResponse() as HttpWebResponse;
                //get the fed-auth cookie
                if (response.Cookies.Count > 0)
                {
                    var fedAuth = response.Cookies["FedAuth"];
                    if (fedAuth != null)
                    {
                        cookies.Add(fedAuth);
                    }
                    else
                    {
                        cookies.Add(response.Cookies);
                    }
                }
                else if (!string.IsNullOrEmpty(response.Headers[HttpResponseHeader.SetCookie]))
                {
                    string[] cookie = response.Headers[HttpResponseHeader.SetCookie].Split(';');

                    Cookie fedCookie = null;

                    for (int index = 0; index < cookie.Length; index++)
                    {
                        string[] cookieNameValue = cookie[index].Split('=');

                        switch (cookieNameValue[0].ToLower())
                        {
                            case "fedauth":
                                fedCookie = new Cookie(cookieNameValue[0], cookieNameValue[1]) { Domain = domain.Replace("https://", string.Empty) };
                                break;

                            case "expires":
                                fedCookie.Expires = Convert.ToDateTime(cookieNameValue[1]);
                                break;

                            case "path":
                                fedCookie.Path = cookieNameValue[1];
                                break;

                            case "secure":
                                fedCookie.Secure = true;
                                break;
                        }
                    }
                    cookies.Add(fedCookie);

                }
                else
                {
                    throw new ApplicationException("FedAuth cookie not received from Sharepoint. Please contact sharepoint administrator for further assistance.");
                }

                #endregion

                // Get the page we should hit next (should be Cognos)
                // Step 7: Persist the cookie
                while (response.StatusCode == HttpStatusCode.Redirect)
                {

                    url = response.Headers[HttpResponseHeader.Location];
                    Console.WriteLine(string.Format("Status = {0}, Response URL = {1}

"
, response.StatusDescription, url));

                    if (url.StartsWith("/"))
                        url = rootUrl + url;

                    request = WebRequest.Create(url) as HttpWebRequest;
                    request.CookieContainer = cookies;
                    request.AllowAutoRedirect = false;

                    Console.WriteLine(string.Format("Request URL = {0}
"
, request.RequestUri));

                    response = (HttpWebResponse)request.GetResponse();
                    cookies.Add(response.Cookies);

                }

                var lists = new Lists { CookieContainer = cookies };

                #region Code to update metadata for "My Submitted Content" list
                var camlcmd = new StringBuilder();
                camlcmd.Append("");
                foreach (var field in mmsParams.ListItemFields)
                {
                    camlcmd.AppendFormat
                        (
                            "{1}",
                            field.Key.Replace(" ", "_x0020_"),
                            field.Value
                        );
                }
                camlcmd.Append("
");

                var updates = (new XmlDocument()).CreateElement("Batch");
                updates.InnerXml = camlcmd.ToString();

                var resp = lists.UpdateListItems(mmsParams.PublishListName, updates);
                #endregion

                #region List Service response
                if (resp.FirstChild.FirstChild.InnerText == "0x00000000")
                {
                    var listitemid = resp.ChildNodes[0].ChildNodes[2].Attributes["ows_ID"].Value;
                    foreach (string attachment in mmsParams.Attachments)
                    {
                        lists.AddAttachment
                            (
                                mmsParams.PublishListName,
                                listitemid,
                                Path.GetFileName(attachment),
                                ReadBytes(attachment)
                            );
                    }
                }
                else
                {
                    throw new Exception("No field was found with that name. Check the name, and try again");
                }
                #endregion
            }
            finally
            {
                // Step 9: Delete the cookie from cache when done
                //DeletePersistentCookies(cookies);
            }
        }

        public static string ResponseToString(HttpWebResponse response)
        {
            // Get the stream containing content returned by the server and.
            // Open the stream using a StreamReader for easy access.
            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                // Read the content.
                return reader.ReadToEnd();
            }
        }
        public static NameValueCollection GetHTMLInputTags(string responseString)
        {
            var htmlDocument = new HtmlDocument();
            htmlDocument.LoadHtml(responseString);
            var nodeCollection = htmlDocument.DocumentNode.SelectNodes("//input");
            var tags = new NameValueCollection();
            for (var index = 0; index < nodeCollection.Count; index++)
            {
                var attributeCollection = nodeCollection[index].Attributes;
                var type = attributeCollection["type"] != null ?
                                    attributeCollection["type"].Value :
                                    string.Empty;
                if (type.ToLower().Equals("submit") || type.ToLower().Equals("button")) continue;
                var name = attributeCollection["name"] != null
                                  ? attributeCollection["name"].Value
                                  : string.Empty;
                var value = attributeCollection["value"] != null
                                   ? attributeCollection["value"].Value
                                   : string.Empty;
                if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))
                    tags.Add(name, value);
            }
            return tags;
        }