 |
|
AC's Blog Quick Links
|
|
SharePoint Quick Links
|
Article Categories
|
Archives
February, 2012 (2)
January, 2012 (12)
December, 2011 (6)
November, 2011 (3)
October, 2011 (17)
September, 2011 (8)
August, 2011 (6)
July, 2011 (7)
June, 2011 (13)
May, 2011 (9)
April, 2011 (15)
March, 2011 (1)
February, 2011 (6)
January, 2011 (5)
December, 2010 (11)
November, 2010 (6)
October, 2010 (12)
September, 2010 (5)
August, 2010 (4)
July, 2010 (5)
June, 2010 (6)
May, 2010 (11)
April, 2010 (11)
March, 2010 (9)
February, 2010 (9)
January, 2010 (3)
December, 2009 (10)
November, 2009 (15)
October, 2009 (15)
September, 2009 (7)
August, 2009 (4)
July, 2009 (10)
June, 2009 (8)
May, 2009 (2)
April, 2009 (9)
March, 2009 (6)
February, 2009 (16)
January, 2009 (6)
December, 2008 (12)
November, 2008 (12)
October, 2008 (27)
September, 2008 (13)
August, 2008 (14)
July, 2008 (14)
June, 2008 (12)
May, 2008 (23)
April, 2008 (12)
March, 2008 (15)
February, 2008 (13)
January, 2008 (12)
December, 2007 (10)
November, 2007 (8)
October, 2007 (15)
September, 2007 (20)
August, 2007 (21)
July, 2007 (16)
June, 2007 (8)
May, 2007 (25)
April, 2007 (16)
March, 2007 (18)
February, 2007 (18)
January, 2007 (12)
December, 2006 (16)
November, 2006 (13)
October, 2006 (18)
September, 2006 (22)
August, 2006 (27)
July, 2006 (23)
June, 2006 (23)
May, 2006 (23)
April, 2006 (9)
March, 2006 (17)
February, 2006 (15)
January, 2006 (23)
December, 2005 (31)
November, 2005 (32)
October, 2005 (38)
September, 2005 (53)
August, 2005 (30)
July, 2005 (63)
June, 2005 (30)
May, 2005 (59)
April, 2005 (29)
March, 2005 (74)
February, 2005 (27)
January, 2005 (22)
December, 2004 (32)
November, 2004 (42)
October, 2004 (39)
September, 2004 (20)
August, 2004 (14)
July, 2004 (27)
June, 2004 (40)
May, 2004 (5)
April, 2004 (6)
March, 2004 (16)
February, 2004 (26)
January, 2004 (23)
December, 2003 (7)
November, 2003 (14)
October, 2003 (20)
September, 2003 (4)
|
Post Categories
|

|
 |
|
 Thursday, February 02, 2012
I’m very much looking forward to this show every year. I’ve got a handful of sessions I’m co-presenting with other folks as the show is doing something a bit different. I’ll be in the Developer track and as it states on the site: This track is for all the Developers out there who are just starting a SharePoint journey of discovery and for those developers who have been developing for a while and now need to hone their skills to a more advanced level. There is so much that you can do with SharePoint where do you start, and what is the correct way to take a design all the way through to a finished solution deployed live in your production farm. The Developer track in 2012 will be a unique track with a complete 3 day focus on taking a concept all the way through its build, test and deployment process and showing how in the real world what situations a developer can come across and how those situations are troubleshot and resolved. Unlike normal session based conferences this year we plan on expanding on the basic knowledge and going as deep as is needed, so if a topic needs 2 sessions to cover it thoroughly then 2 sessions will be scheduled so you get all the information you need when you go back to the office. Cool and unique idea huh? Can’t wait to see how it all comes out with my colleagues! Go register today & hope to see you there! » The International SharePoint Conference London 2012
 Wednesday, February 01, 2012
In the past I’ve complained about the Salesforce SOAP API for reading/writing your CRM databases. Last year Salesforce added a new API, one founded on RESTful principals, for developers to work with. I wish it was implemented as an OData service, but I guess the Salesforce guys are stuck behind the times. At any rate, I had a need to read/write to a Salesforce instance and couldn’t bear to use their SOAP API again so I decided to give the REST API a go. Their developer site doesn’t do that much in the way of help for .NET developers (there is some, but not much)… everything is really skewed towards PHP or their own APEX language. After some searching I found Dan Boris’ series of Salesforce related posts. These are good and he covers a lot of good things such as: - Authentication:
- Reading Data
- Writing Data
Dan’s posts talk about using the method of authentication where you create an app that contains an embedded browser control and you get the user using t your app to login to Salesforce. Then your app grabs the OAuth token and include that with all future requests. Before you do this you need to configure a new remote access app for your Salesforce account. This is done by logging in and going to SETUP > DEVELOP > REMOTE ACCESS. Click NEW and create a new remote access app. One of the fields it will give you is a callback URL that is required. This is used by Salesforce to redirect the user back to a specific URL after a successful login. In a web app this makes sense but not if you want to use this within a console app or a service. What I do is put just a dummy URN in there that I’ll look for later like resttest:callback. Now, Dan’s stuff works great in many cases, but not if you want to create an app that runs like a service and automatically logs in and does some stuff with the API without user interaction. The way you authenticate with Salesforce is using OAuth 2.0. OAuth 2.0 supports multiple authentication flows and Salesforce supports many of them as outlined in their SDK: Authenticating Remote Access Application OAuth & discussed on their DeveloperForce site: Digging Deeper into OAuth 2.0 on Force.com. In my scenario I want to focus on creating an app that runs as a service to use the REST API without any user action required for logging in. This is the least secure because it means I have to store a username & password somewhere, but that's just the ante for playing the game. So, in this case I want to use the OAuth 2.0 Username & Password Flow. So, to authenticate you do something like this using the OAuth 2.0 Username & Password flow: 1: private void AuthenticateToSalesforce(){ 2: string uri = "https://login.salesforce.com/services/oauth2/token"; 3: 4: var webClient = new WebClient() { 5: BaseAddress = uri 6: }; 7: 8: var collection = new NameValueCollection(); 9: collection.Add("grant_type", "password"); 10: collection.Add("client_id", CONSUMER_KEY); 11: collection.Add("client_secret", CONSUMER_SECRET); 12: collection.Add("username", SALESFORCE_USERNAME); 13: collection.Add("password", SALESFORCE_PASSWORD_AND_SECRETKEY); 14: 15: byte[] responseBytes = webClient.UploadValues("", "POST", collection); 16: string response = Encoding.UTF8.GetString(responseBytes); 17: string decodedResponse = HttpUtility.UrlDecode(response); 18: JavaScriptSerializer js = new JavaScriptSerializer(); 19: var token = js.Deserialize<TokenResponse>(decodedResponse); 20: } 21: 22: public class TokenResponse { 23: public string id { get; set; } 24: public string issued_at { get; set; } 25: public string refresh_token { get; set; } 26: public string instance_url { get; set; } 27: public string signature { get; set; } 28: public string access_token { get; set; } 29: }
As you can see I’m creating a Web request and passing in a handful of things in the header. Specifically I’m passing in the grant_type of “password” to signal I want to use the OAuth 2.0 Username & Password flow. I’m also passing in the consumer key & secret you get from creating the remote access app in your Salesforce account and finally the username & password to authenticate with. This will return a JSON array (you can also get a XML response if you like) which I deserialize into a custom object that will pull everything I need. Specifically I need the instance_url (which is the URL of my Salesforce account) and the access_token which is what you need to include in all future requests.
Once you have the token, you can use the REST API to read & write data like Dan shows in his posts I linked to above, or like this:
1: public void QuerySalesforce(){ 2: // build LEAD query 3: XDocument xDoc = XDocument.Load(@"SalesForceSchema.xml"); 4: var fields = from x in xDoc.Root.Element("Lead").Elements("Field") 5: select x.Attribute("SfName").Value; 6: string query = String.Format("SELECT {0} FROM Lead 7: WHERE Email = 'something@email.com'" 8: , string.Join(",", fields)); 9: 10: string sfQuery = String.Format("{0}/services/data/v23.0/query?q={1}", 11: token.instance_url, 12: query); 13: HttpWebRequest request = HttpWebRequest.Create(sfQuery) as HttpWebRequest; 14: request.Headers.Add("Authorization", "OAuth " + token.access_token); 15: request.ContentType = "application/json"; 16: request.Method = "GET"; 17: 18: WebResponse webResponse = request.GetResponse(); 19: var sr = new System.IO.StreamReader(webResponse.GetResponseStream()); 20: string json = sr.ReadToEnd(); 21: var leads = js.Deserialize<sfdcLeadCollection<sfdcLeadForCollection>> 22: (HttpUtility.UrlDecode(json)); 23: } 24: 25: public class sfdcLeadCollection<T> { 26: public bool Done { get; set; } 27: public int TotalSize { get; set; } 28: public string nextRecordsUrl { get; set; } 29: public List<T> Records { get; set; } 30: } 31: 32: public class sfdcAttributes { 33: public string Type { get; set; } 34: public string Url { get; set; } 35: } 36: 37: public class sfdcLeadForCollection : sObjectLead { 38: public sfdcAttributes Attributes { get; set; } 39: } 40: 41: public class sObjectLead { 42: public string Id { get; set; } 43: public string Email { get; set; } 44: public string FirstName { get; set; } 45: public string LastName { get; set; } 46: public string Company { get; set; } 47: public string Phone { get; set; } 48: public string MobilePhone { get; set; } 49: public string Fax { get; set; } 50: public string Website { get; set; } 51: public string Street { get; set; } 52: public string City { get; set; } 53: public string State { get; set; } 54: public string Country { get; set; } 55: public string PostalCode { get; set; } 56: }
Technorati Tags: salesforce, rest api
 Monday, January 30, 2012
The folks who bring you SharePoint Connections are putting on another free online virtual conference. The show, Afraid of the Dark? Keep SharePoint Running!, is on February 16th, 2012. This one day show has a killer price point – it’s FREE!!! I’ll be presenting one session, Out of the Sandbox and into the Cloud: Build Your Next SharePoint App on Azure. Hope to see you there! » SharePoint Virtual Conference – Afraid of the Dark? Keep SharePoint Running
 Saturday, January 21, 2012
When I saw the presser months ago with Jeff Bezos, someone I highly respect in this business and one of the few true visionaries, I jumped and did what I try not to do and make an impulse purchase on something that expensive. When I got it I loved it, gave it a few days and wrote a review I posted here. Now after two months, I wanted to post some more thoughts. First, I still really like the device and I’m glad I got it. But I have to say that I don’t love it. You can’t beat the price for what you get, but there are a few aspects to it that I would need to see resolved for it to be a good iPad killer: - Performance – I’d gladly pay a little more to have a better processor in it. The keyboard is sluggish, too sluggish to take notes with or be active on email. Even with the bigger screen, I’d rather use my phone to do mobile messaging. At first I thought this was a software issue, but maybe it isn’t as Amazon hasn’t fixed it. I don’t notice the sluggishness in all apps so that says software to me.
- Storage – Again, I’d pay more for more space… even if it was a removable card. I like to put movies on my tablet to watch when I travel. Streaming from Amazon Prime isn’t going to solve that “want”. You pay for metered bandwidth if you travel (I have a Verizon Mifi 4GLTE hotspot, but I don’t want to use 80% of my monthly usage on movies… I use it for work). Hotel connectivity sucks… even the internet connection in this airport lounge I’m in as I write this sucks (Paris’s Charles de Gaul airport).
- I have ripped some movies and put them on my Kindle Fire, but I only have room for one or two at a time unfortunately. But it does play them great!
- All Cloud – This ties into storage. I like the idea of having my stuff in the cloud… hell I love the cloud… but I want to sync my stuff down to my device. You aren’t always connected when you want your content or want to pay through the nose for bandwidth.
- Reading – I put a ton of work related PDF books and articles on it… and for that it’s great. But if I’m reading a novel, I’m using my Kindle 2nd Generation and the eInk. Nothing surpasses that for quality reading.
- Battery – Sure isn’t nearly as good as the regular Kindle due to the great screen… but I expected more after having an iPad for a while.
The other thing I love about the Kindle Fire is the form factor. I pickup an iPad now and it feels massive… way too big. The most glaring thing that the Kindle Fire has shown me is how crappy the Android OS is. This feels like it is so clobbled together… apps freeze, you have to force close them, the UI sucks… I’m not a fan. Microsoft and Apple have it right when their mobile OS’. I’m more of a fan of Windows Phone than iOS, but maintaining control and blocking customization of the OS is definitely the way to go. Is it an iPad replacement? Maybe for some… maybe for me (see above: I haven’t picked it up since I got the Kindle Fire). I just can’t get past the fact the entry point for an iPad is $500 and goes up to $830! Sorry Apple, but that’s absurd… the iPad isn’t 2x as good (when you factor in the closest model to the Fire… WIFI only & 16GB @ $499) price wise as the Kindle Fire. All in all, it’s a great device and you’re getting what you pay for: a very inexpensive & versatile tablet. I do like the Kindle Fire more than my iPad (1st generation)… in fact I haven’t picked up my iPad since I got the Kindle Fire (and I don’t miss it). It’s turned into the family iPad and my son uses it the most. I’m very eager, and will get, a tablet based on Windows 8 when it comes out mid year. Not saying Windows 8 will be great, just that it will be interesting how well it, and the devices that are out for it, executes. So far, I like what I see. So for me, Kindle Fire > iPad… but we’ve yet to hit that tablet sweet spot IMHO.
 Friday, January 13, 2012
A month or so ago I blogged about a new offering we have at Critical Path Training, a 2-day SharePoint 2010 Developer Roadshow. Our first delivery will be in Boston, February 15-16, 2012 at the Museum of Science. After the first day of the event (February 15) head over to Mr. Dooley’s Boston Tavern for drinks and to shoot the breeze … it’s a SharePint after all! Registration for the event runs $599 but if you register before the end of the weekend (January 15) you’ll get $100 off to make it $499!
 Wednesday, January 11, 2012
This post is part of a series on Office365/SharePoint Online, Windows Azure and Authentication. The other posts in this series are as follows:
In this last post in my Office365/SharePoint Online + Windows Azure + Authorization blog series, I want to introduce a little helper project I am using. To make life easier I created a little O365 authorization helper library that does a lot of the heavy lifting for you. It covers two of the three things I outlined in my series as workarounds.
Code samples I show in this post were taken from a code sample CPT's Office365/SharePoint Online Claims Authentication Helper Library… you can get the code from the Critical Path Training site’s Members section… look in the Code Samples section.
Introducing the Claims Auth Friendly ClientContext: ClaimsClientContext
First it creates a special Client Site Object Model (CSOM) ClientContext object. This object has a few properties needed for authenticating with Microsoft Online (MSO) to obtain the SAML token. It then rewrires the ClientContext so that every request includes the SAML token:
1: namespace CriticalPathTraining.Office365.AuthLibrary {
2: public class ClaimsClientContext : ClientContext {
3: public string MsoUsername { get; set; }
4: public string MsoPassword { get; set; }
5: public string MsoRootSiteCollectionUrl { get; set; }
6:
7: public ClaimsClientContext(string webFullUrl) : base(webFullUrl) { }
8: public ClaimsClientContext(Uri webFullUrl) : base(webFullUrl) { }
9:
10: private MsOnlineClaimsHelper _claimsHelper;
11: /// <summary>
12: /// Microsoft Online claims helper used to authenticate to
13: /// SharePoint Online.
14: /// </summary>
15: private MsOnlineClaimsHelper MsftOnlineClaimsHelper {
16: get {
17: if (_claimsHelper == null) {
18: _claimsHelper = new MsOnlineClaimsHelper(
19: MsoUsername,
20: MsoPassword,
21: MsoRootSiteCollectionUrl);
22: }
23: return _claimsHelper;
24: }
25: }
26:
27: /// <summary>
28: /// Rewire event for client context so that
29: /// every request includes authenticated cookies.
30: /// </summary>
31: protected override void OnExecutingWebRequest(WebRequestEventArgs args) {
32: args.WebRequestExecutor.WebRequest.CookieContainer =
33: MsftOnlineClaimsHelper.CookieContainer;
34: }
35: }
36: }
Usage is very simple… the downloadable library includes a test project that shows the usage:
1: [TestMethod]
2: public void CliamsClientContextTest() {
3: using (var context = new ClaimsClientContext(MSO_SPSITE_URL) {
4: MsoUsername = MSO_USERNAME,
5: MsoPassword = MSO_PASSWORD,
6: MsoRootSiteCollectionUrl = MSO_ROOT_SPSITE_URL
7: }) {
8: // get the web
9: var web = context.Web;
10: context.Load(web, w => w.Title);
11: context.ExecuteQuery();
12:
13: Assert.IsNotNull(web.Title);
14: Assert.IsTrue(web.Title.Length > 0);
15:
16: Console.WriteLine("Retrieved site title:" + web.Title);
17: }
18:
19: }
Introducing the Claims Friendly Web Client: ClaimsWebClient
The other thing I give you is a special version of the WebClient class that’s makes working with claims a bit easier. It has a single property where you specify the CookieContainer that will contain the SAML token. The library exposes the samples Wictor Wilen provided on to do the authentication for you and generate the CookieContainer:
1: namespace CriticalPathTraining.Office365.AuthLibrary {
2: public class ClaimsWebClient : WebClient {
3: /// <summary>
4: /// Cookies that should be included on every Web request.
5: /// </summary>
6: public CookieContainer CookieContainer { get; set; }
7:
8: /// <summary>
9: /// Override base GetWebRequest() method to always include
10: /// cookies if they were specified.
11: /// </summary>
12: protected override WebRequest GetWebRequest(Uri address) {
13: var request = base.GetWebRequest(address);
14: if (request is HttpWebRequest && CookieContainer != null)
15: ((HttpWebRequest)request).CookieContainer = CookieContainer;
16:
17: return request;
18: }
19: }
20: }
In the associated test project you’ll also find the usage for this as well:
1: [TestMethod]
2: public void ClaimsWebClientTest() {
3: // file to download
4: string fileToDownload = "/_layouts/images/siteIcon.png";
5:
6: var claimsHelper = new MsOnlineClaimsHelper(
7: MSO_USERNAME,
8: MSO_PASSWORD,
9: MSO_ROOT_SPSITE_URL);
10: using (var webClient = new ClaimsWebClient() {
11: CookieContainer = claimsHelper.CookieContainer
12: }) {
13: // get the file
14: var fileStream = ((ClaimsWebClient)webClient).OpenRead(
15: string.Format("{0}{1}", MSO_SPSITE_URL, fileToDownload)
16: );
17:
18: // download & write local
19: string tempFilePath = Path.GetTempFileName();
20: var tempFile = File.Open(tempFilePath, FileMode.OpenOrCreate);
21: fileStream.CopyTo(tempFile);
22: fileStream.Close();
23: tempFile.Close();
24:
25: Console.WriteLine("Downloaded file to:" + tempFilePath);
26:
27: // make sure file exists & bigger than 0 bytes
28: Assert.IsTrue(File.Exists(tempFilePath));
29: var fileInfo = new FileInfo(tempFilePath);
30: Assert.IsTrue(fileInfo.Length > 0);
31: }
32: }
Last but not least, for completeness I threw in a test for working with any of the SharePoint *.ASMX or *.SVC Web services. You don’t need any special helpers here as they include a CookieContainer class already:
1: [TestMethod]
2: public void WebServiceTest() {
3: XmlNode results;
4:
5: var claimsHelper = new MsOnlineClaimsHelper(
6: MSO_USERNAME,
7: MSO_PASSWORD,
8: MSO_ROOT_SPSITE_URL);
9: using (var client = new Lists() {
10: Url = string.Format("{0}_vti_bin/Lists.asmx", MSO_SPSITE_URL),
11: UseDefaultCredentials=true,
12: CookieContainer = claimsHelper.CookieContainer
13: }) {
14: results = client.GetList("Shared Documents");
15: }
16:
17: Assert.IsNotNull(results);
18: }
This post is part of a series on Office365/SharePoint Online, Windows Azure and Authentication. The other posts in this series are as follows:
Now let's see how we can address the authentication fixes for each of the different ways you can access SharePoint remotely. In this post I'll cover each of the specific tools (REST or OData / CSOM / Web Services / WebClient) and how to address each of the tricks. Each one has it's pros & cons, hence why I had to use all four tools in my demo in my breakout session Out of the Sandbox and into the cloud: Build your next SharePoint app on Azure at the Microsoft SharePoint Conference 2011 (see that link for where you can download the sample).
Any code samples I show in this post were taken from my session Out of the Sandbox and into the cloud: Build your next SharePoint app on Azure at the Microsoft SharePoint Conference 2011… you can get the demo code from the Critical Path Training site’s Members section… look for the AC's SharePoint Conference 2011 Sessions download in the Presentations section.
For all the samples below, I created a private property in my class called MsftOnlineClaimsHelper that creates a local instance of the MSO helper and automatically authenticates.
1: private MsOnlineClaimsHelper _claimsHelper;
2: /// <summary>
3: /// Microsoft Online claims helper used to authenticate to SharePoint Online.
4: /// </summary>
5: private MsOnlineClaimsHelper MsftOnlineClaimsHelper {
6: get {
7: if (_claimsHelper == null) {
8: _claimsHelper = new MsOnlineClaimsHelper(
9: RoleEnvironment.GetConfigurationSettingValue("SharePointUsername"),
10: RoleEnvironment.GetConfigurationSettingValue("SharePointPassword"),
11: RoleEnvironment.GetConfigurationSettingValue("SharePointRootSiteUrl"));
12: }
13: return _claimsHelper;
14: }
15: }
CSOM Client Context & CBA Challenges
One of the most common ways to work with SharePoint 2010 from off the SharePoint server is using the CSOM. Authentication with the CSOM is pretty straight forward using the ClientContext object. The trick comes into play with claims based authentication (CBA).
When you want to switch to FBA it's a simple property switch on the ClientContext, but as I previously stated there is no such way to do this for CBA. What you need to do is rewire the ClientContext so that every request it makes to a site collection includes a SAML token to authenticate the request. You do this by trapping the ExecutingWebRequest event of the ClientContext and injecting the cookie container generated by the MSO helper into all requests:
1: private ClientContext _clientContext;
2: /// <summary>
3: /// CSOM client context.
4: /// </summary>
5: private ClientContext CsomClientContext {
6: get {
7: if (_clientContext == null) {
8: _clientContext = new ClientContext(
9: RoleEnvironment.GetConfigurationSettingValue("SharePointSiteUrl")
10: );
11:
12: // wire up claim helper to include SAML tokens (cookies) in all requests
13: _clientContext.ExecutingWebRequest +=
14: (webRequestSender, args) => {
15: args.WebRequestExecutor.WebRequest.CookieContainer
16: = MsftOnlineClaimsHelper.CookieContainer;
17: };
18: }
19: return _clientContext;
20: }
21: }
Now, almost all requests the ClientContext make will include the SAML token! I say "almost" because there is a bit of an issue with the ClientContext. There is a method called File.OpenBinaryDirect() that you can use to download a file from SharePoint. For some reason this method doesn't raise the same ExecutingWebRequest event so your token isn't handled! Ouch… oversight in the API me thinks… regardless, you can get around this using a stock Web Client...
Web Request & CBA Challenges
The way you can address the lack of passing along the SAML token to SPO when you try to open and download a file using the File.OpenBinaryDirect() method is to simply create a simple Web request that will download the file. However this process also needs a little bit of work to pass along the SAML token. What I did was create a custom version of the WebClient class that did this for you as follows:
1: namespace AndrewConnell.ACsCichlids.StoreFront {
2: public class ClaimsFriendlyWebClient : WebClient {
3: private CookieContainer _cookieContainer;
4: public CookieContainer CookieContainer {
5: get { return _cookieContainer; }
6: set { _cookieContainer = value; }
7: }
8:
9: protected override WebRequest GetWebRequest(Uri address) {
10: var request = base.GetWebRequest(address);
11: if (request is HttpWebRequest)
12: ((HttpWebRequest)request).CookieContainer = _cookieContainer;
13:
14: return request;
15: }
16: }
17: }
This method is handy when you want to download a file from a site collection. To use it you simply pass in the MSO helper's cookies and they will be included on all requests:
1: using (var webclient = new ClaimsFriendlyWebClient()
2: { CookieContainer = MsftOnlineClaimsHelper.CookieContainer }
3: ) {
4: // download file into a memory stream
5: var fileStream = ((ClaimsFriendlyWebClient)webclient).OpenRead(cichlidPicture.OriginalUri);
6:
7: // create & save blob
8: var blob = AzureStorageContainer.GetBlobReference(cichlidPicture.ImportedFilename);
9: blob.UploadFromStream(fileStream);
10: }
REST / OData / Web Services & CBA Challenges
My preferred way to read/write data to SharePoint lists is using the RESTful OData service ListData.svc. This service, like all the other Web services that are included with SharePoint 2010 (*.ASMX & *.SVC), don't understand claims by default. When you want to authenticate for a Windows or FBA site you have to create a network credential object and set it as a property on the service proxy.
However this isn't available when it comes to authenticating with CBA. Like the ClientContext, you need to rewire the calls to make sure they include the SAML token in each request. This is pretty simple as most services, like the Lists.asmx service, includes a CookieContainer property:
1: XmlNode results;
2:
3: // call lists.asmx web service to get attachments for each item
4: // use same "cookie container" technique to authenticate
5: using (var client = new Lists() {
6: Url = siteUrl + "/_vti_bin/Lists.asmx",
7: UseDefaultCredentials = true,
8: CookieContainer = MsftOnlineClaimsHelper.CookieContainer
9: }) {
10: results = client.GetAttachmentCollection(
11: RoleEnvironment.GetConfigurationSettingValue("SharePointManagementListName")
12: , listItemId.ToString()
13: );
14: }
There you have it... hopefully this series & code samples will help you authenticate into your site collections in SharePoint Online!
This post is part of a series on Office365/SharePoint Online, Windows Azure and Authentication. The other posts in this series are as follows:
In my previous post in this series I talked about how authentication works with Office365 (O365) & SharePoint Online (SPO). You first authenticate with Microsoft Online (MSO) and then your browser passes along the SAML token with each request to site collections in SPO.
The first thing we need to do when accessing SPO programmatically is to understand how we authenticate with MSO and get the SAML token. Thankfully Microsoft provides a sample to help with the authentication piece. What you need is to make sure you have the Windows Identity Framework Runtime installed first. The main class that Wictor Wilen provides for authenticating to MSO is MsOnlineClaimsHelper. This class takes three parameters in the constructor:
- MSO Username of the account to authenticate with
- MSO Password of the account to authenticate with
- URL of the root site collection for your SPO account - note this is the root site collection which may not necessarily be the site collection you are interested in, but it is needed to authenticate and get the key
The MsOnlineClaimsHelper class has a public property, CookieContainer (which is also of type System.Net.CookieContainer), that you'll use to get the SAML token from MSO to attach to future requests. When the CookieContainer property is accessed, if null, the MsOnlineClaimsHelper will go authenticate and parse the results to extract the SAML token and store it in the cookie container.
Check out the code sample I mentioned previously in this post. What you're looking for are two files in the MSDN folder of the ACsCichlids.StoreFront project & the CSOM redistributable. These two files are the aforementioned MsOnlineClaimsHelper.cs & a file it depends on, WcfClientContracts.cs. Copy them into your project and that's all you need in order to authenticate.
Here's just a little code from a simple console app that shows me authenticating into my SharePoint Online site collection:
1: static void Main(string[] args) {
2:
3: string msoUsername = "jack.sparrow@aconn.onmicrosoft.com";
4: string msoPassword = "[password]";
5: string msoRootSpSite = "https://aconn.sharepoint.com/";
6:
7: var msoHelper = new MsOnlineClaimsHelper(
8: msoUsername,
9: msoPassword,
10: msoRootSpSite);
11:
12: CookieContainer cookieJar = msoHelper.CookieContainer;
13:
14: }
 Tuesday, January 10, 2012
This post is part of a series on Office365/SharePoint Online, Windows Azure and Authentication. The other posts in this series are as follows:
Creating applications in SharePoint 2010, specifically the hosted environment Office365/SharePoint Online, when you want to communicate with applications and services in Windows Azure you are limited to client-side communications or using Business Connectivity Services (BCS). This is because all server-side code must run in the sandbox and that blocks all external web service calls.
What's the Problem?
However when you create an application in Windows Azure, or anything that wants to talk to SharePoint Online, regardless of the tools you use to connect to SharePoint Online (REST or OData / CSOM / Web Services / WebClient) you'll quickly find you are having authentication issues. The reason for this is because SharePoint Online is configured for claims authentication and use Microsoft Online (MSO) for authentication. That's why when you go to your SharePoint Online site, you are sent to what looks similar to a LiveID login page but it is branded for Office 365:
So…. what's the problem? The root problem is that none of the tools I mentioned above (REST or OData / CSOM / Web Services / WebClient) understand how to authenticate to a system that's configured for claims based authentication (CBA). Thankfully each one can be rewired a bit as to make it work but it takes a bit of work.
Quick Primer on Claims Based Authentication
If you aren't versed in CBA, let me point to two great links where you can get more information. Check out MSDN's Patterns & Practices group: An Introduction to Claims but my favorite explanation one is by Donovan Follette's real world example here. Basically here's how it works, borrowing a picture from the P&P article:
The user tries to hit a resource that's protected by CBA such as a site collection in SharePoint Online (SPO). Because the user isn't authenticated, the user is sent to a login page which in this case is Microsoft Online (MSO). The user then logs (#1) in and is given a token (#2) that's in the format of Security Assertion Markup Language (SAML). The user puts this token in a cookie in the HTTP header and goes back to the SPO site collection (#3). Because the site collection gets the authentication token and the hosting SharePoint installation trusts the source that created the token (using some digital signatures & trust configurations that were setup ahead of time by administrators), the user is allowed in.
OK… So… How Do you Fix the Tools for CBA?
Here's the root of the problem: none of the four tools know how to authenticate with MSO and how to pass the SAML token along to the target system. The light bulb might have just gone off for a few of you… you may have been trying to programmatically authenticate with MSO and then make your request only to get a 401 - Access Denied. The reason you get that is because you aren't passing along your token in the header of your requests… you're being denied because you're trying to hit the resource as an unauthenticated (aka: anonymous) user.
The big picture fix for this is very simple:
- Programmatically authenticate with MSO
- Parse the response to get the SAML token
- Attach the token to all requests to site collections in SharePoint Online
Thankfully a lot of other folks have done a lot of the heavy lifting for us. I don't want to duplicate the work they've done and you should read these. Each of them have various code downloads for things you need (like the Windows Identity Foundation runtime & SDK & the CSOM redistributable (& don't forget about the CSOM redistributable service pack 1 x86 or x64). Almost all of them have associated code downloads filled with helpful stuff.
- MSDN:
- Steve Peshka: Mr. Claims for SharePoint
- Wictor Wilen: SharePoint MCM & MVP who created some great code samples
- Chris Johnson: Former Microsoft Sr. Technical Project Manager who created a nice rollup app demonstrating what you learned from above links
Up Next…
Now that you understand how the authentication works & the challenges each of our client tools & techniques has with it, we need to take a moment to get past the first step: authenticate with MSO to get a SAML token!
In the previous series I talked about how you can leverage both SharePoint 2010 and Windows Azure to create compelling & powerful integrated solutions. In the introduction post I talked about how I did a session at Microsoft's SharePoint Conference 2011 on integrating the two. In building out the demo for that I ran into some challenges when I tried to have my custom Windows Azure solution talk to and interact with a hosted SharePoint 2010 site collection living in my Office 365 SharePoint Online space. I ran into a few challenging spots when I tried using any of the four remote data access techniques available to developers:
- REST / OData / WCF Data Services (ListData.svc)
- Client Side Object Model (CSOM)
- Web Services (ASP.NET ASMX / WCF SVC)
- Web Requests (WebClient)
This blog series will talk about some of these challenges and how to overcome them. The last post will introduce a little helper library you can get for free from the Critical Path Training Member's only download site. Let's get to it!
|
|
SharePoint 2010 Training
Looking for SharePoint 2010 training for developers, administrators, SharePoint Designer 2010 and end users? Look no further! My company, Critical Path Training offers the best SharePoint training around!
|
|
|