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("