Using SharePoint's Client object Model against a SharePoint site that is not using IWA(Kerberos or NTLM) is not supported out of the box(least not as clean as I would like). If the site is using Forms Based Auth and you can prompt the user for user name and password it can be done by using the following:
Using the Client Object Model with a Forms Based Auth Site in SharePoint 2010
ClientContext ctx =
new
ClientContext(someSiteUrl);
ctx.AuthenticationMode = ClientAuthenticationMode.FormsAuthentication;
ctx.FormsAuthenticationLoginInfo =
FormsAuthenticationLoginInfo(myUserName, myUserPwd);
//get the web
Web w = ctx.Web;
//LOAD LISTS WITH ALL PROPERTIES
var lists = ctx.LoadQuery(w.Lists);
//execute the query
ctx.ExecuteQuery();
foreach
(List theList
in
lists)
{
//do something here
}
The above approach is ok but means storing the user name and password for the user everytime you want to call to SharePoint with Client OM as the user logged in to your app. Doing so is probably not the best practice and the alternative is to prompt the user before every call to SharePoint from the calling application. Other approaches I saw popped up a WebControl like a mini-browser for the user to auth to SharePoint then they used some COM calls to get the Auth Cookies as it was set HTTPONLY and not directly accessible. I have used the following approach to solve this problem. In a later article I will add the functionality to utilize this approach for Authenticating to SharePoint site using a custom STS for authentication.
This approach was built to support ASP.NET web applications calling into SharePoint 2010 via the Client Obect Model. However the underlying concept can be used from console apps, win forms and windows services. This solution took a lot of fiddler snooping and debugging and seems like it should be easier to do this but this is what I was able to get working. Once I got it working it did not seem too bad but sure seems like a Rube Goldberg approach. This approach assumes that the ASP.NET application and SharePoint Site are using the same user respository, In my case i was using SQL Server Membership and Role Provider. This ensures that logging into the ASP.NET Forms Auth Login Page can use the same user/pass to back channel log into SharePoint. The follow up article on using STS makes this a moot point.
Outline
On the Login EventHandler that your forms authentication page uses authenticate to you call to SharePoint to get an auth cookie. If using the ASP.NET Login control the LoggingIn Event is a good spot.
protected
void
LoginUser_LoggingIn(
object
sender, LoginCancelEventArgs e)
// URL to the SharePoint Forms Login Page
String SiteLogin=
"https://my.FBASharePointSite.com/_forms/default.aspx"
;
try
String AuthToken = getAuthToken(SiteLogin, LoginUser.UserName, LoginUser.Password);
catch
(Exception ex)
This method below basically mimics what a browser would do and does a login to the SharePoint forms auth page and captures the FedAuth cookie generated on a successful login. Note: The variables posted to your SharePoint forms auth page may be different especially if you use a custom login page. Fiddler can be a huge help on determining what the values are and what a valid auth post looks like.
private
String getAuthToken(String SiteLogin, String UserName, String Password)
// have a cookie container ready to receive the forms auth cookie
CookieContainer cookies =
CookieContainer();
// Initial hit to SharPoint site
// load EventValidation and ViewState
// Allow AutoRedirects
// set required HTTP HEADERS
System.Net.HttpWebRequest SPHttpWebRequest = (HttpWebRequest)WebRequest.Create(SiteLogin);
SPHttpWebRequest.AllowAutoRedirect =
true
SPHttpWebRequest.UserAgent =
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0.1) Gecko/20100101 Firefox/8.0.1"
SPHttpWebRequest.Accept =
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
SPHttpWebRequest.Headers.Add(
"Accept-Charset"
,
"ISO-8859-1,utf-8;q=0.7,*;q=0.7"
);
SPHttpWebRequest.CookieContainer = cookies;
// Retrieve HTTP Response from the site
HttpWebResponse SPHttpWebResponse = (HttpWebResponse)SPHttpWebRequest.GetResponse();
StreamReader responseReader =
StreamReader( SPHttpWebResponse.GetResponseStream() );
string
responseData = responseReader.ReadToEnd();
responseReader.Close();
// Scrape ViewState and EventValidation from Response
viewState = ExtractViewState(responseData);
eventValidation = ExtractEventValidation(responseData);
// Authentication Request to get forms auth Token through a form post.
HttpWebRequest SPAuthhttpWebRequest = HttpWebRequest.Create(SPHttpWebResponse.ResponseUri)
as
HttpWebRequest;
SPAuthhttpWebRequest.UserAgent =
SPAuthhttpWebRequest.Accept =
SPAuthhttpWebRequest.Headers.Add(
SPAuthhttpWebRequest.ContentType =
"application/x-www-form-urlencoded"
//Specifing the Method
SPAuthhttpWebRequest.Method =
"POST"
SPAuthhttpWebRequest.AllowAutoRedirect =
false
SPAuthhttpWebRequest.CookieContainer = cookies;
//Data to Post to the Page, it is key value pairs; separated by "&"
// Submit button value for this form is "Sign+In"
postData =
String.Format(
"__LASTFOCUS=&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE={0}&__EVENTVALIDATION={1}&ctl00$PlaceHolderMain$signInControl$UserName={2}&ctl00$PlaceHolderMain$signInControl$password={3}&ctl00$PlaceHolderMain$signInControl$login={4}"
viewState, eventValidation, UserName, Password,
"Sign+In"
//Setting the content type, it is required, otherwise it will not work.
//Getting the request stream and writing the post data
using
(StreamWriter sw =
StreamWriter(SPAuthhttpWebRequest.GetRequestStream()))
sw.Write(postData);
//Getting the Respose and reading the result.
HttpWebResponse SPLoginResponse = SPAuthhttpWebRequest.GetResponse()
HttpWebResponse;
ret = SPLoginResponse.Cookies[
"FedAuth"
].Value;
return
ret;
HTML Scraping methods to get ViewSate and EventValidation for post back to SharePoint forms login page
ExtractViewState(
s)
viewStateNameDelimiter =
"__VIEWSTATE"
valueDelimiter =
"value=\""
int
viewStateNamePosition = s.IndexOf(viewStateNameDelimiter);
viewStateValuePosition = s.IndexOf(
valueDelimiter, viewStateNamePosition
viewStateStartPosition = viewStateValuePosition +
valueDelimiter.Length;
viewStateEndPosition = s.IndexOf(
"\""
, viewStateStartPosition);
HttpUtility.UrlEncodeUnicode(
s.Substring(
viewStateStartPosition,
viewStateEndPosition - viewStateStartPosition
)
ExtractEventValidation(
EventValidationDelimiter =
"__EVENTVALIDATION"
EventValidationPosition = s.IndexOf(EventValidationDelimiter);
EventValidationValuePosition = s.IndexOf(
valueDelimiter, EventValidationPosition
EventValidationStartPosition = EventValidationValuePosition +
EventValidationEndPosition = s.IndexOf(
, EventValidationStartPosition);
EventValidationStartPosition,
EventValidationEndPosition - EventValidationStartPosition
Store the FedAuth Cookie in Session for reuse by client object model
"https://spsandbox.acwest.com/_forms/default.aspx"
Session[
"AuthToken"
] = AuthToken;
Now lets use the client object model in a simple aspx page to talk to our FBA SharePoint Site.
Microsoft.SharePoint.Client;
namespace
....
public
partial
class
_Default : System.Web.UI.Page
txtGetSPList_Click(
sender, EventArgs e)
String SPSITEURL =
"https://my.fbasharepointsite.com/"
ClientContext(SPSITEURL);
//use default credentials
ctx.Credentials = CredentialCache.DefaultCredentials;
//configure the handler that will pick up the auth cookie
ctx.ExecutingWebRequest +=
EventHandler<WebRequestEventArgs>(ctx_ExecutingWebRequest);
Console.WriteLine(theList.Title);
ctx_ExecutingWebRequest(
sender, WebRequestEventArgs e)
//TAKE OUT AND PARAMETERIZE
System.Net.CookieContainer cc =
System.Net.CookieContainer();
Cookie SPAuthCookie =
Cookie(
, Session[
].ToString());
SPAuthCookie.Expires = DateTime.Now.AddHours(1);
SPAuthCookie.Path =
"/"
SPAuthCookie.Secure =
SPAuthCookie.HttpOnly =
Uri formsUri =
Uri(SPSITEURL);
SPAuthCookie.Domain = formsUri.Host;
cc.Add(SPAuthCookie);
e.WebRequestExecutor.WebRequest.CookieContainer = cc;
This should return a list of all the lists on the site.
This code needs error handling added as well as better organizations into say a helper library. Additional parameterization of things like SharePoint Urls and the post variables to make it more flexible would also be nice. The idea here was to give you the general idea on how to accomplish the task. Depending on the configuration of your SharePoint site it might also be required to add code to refresh the FedAuth Cookie stored in Session. Otherwise the cookie may expire and the value you stored in session will be useless.
Carsten Siemens edited Revision 23. Comment: typo
Craig Lussier edited Revision 22. Comment: added en-US to tags and title
Rob Reilly edited Revision 1. Comment: Work in Progress!!!!