Tuesday, September 29, 2015

SharePoint Online Web Service Authentication using WCF Client-side behaviour

With the release SharePoint in 2013 and the ever increasing numbers taking up the SharePoint Online offering, it’s a good time to start looking at some of the challenges when moving to these platforms.
SharePoint has traditionally been a presentation technology with its own unique SharePoint development model utilising SharePoint designer and custom Web Part development. With the latest release, SharePoint 2013 that development model has been challenged by a new autonomous development model where the complexities and constraints of SharePoint as a development and deployment platform has been replaced by a service oriented integration platform for multiple independently hosted applications.
SharePoint has always supported a rich and expanding set of services with every release. As part of the move to the new development model a lot of work has gone into improving the “Client side” access into SharePoint by wrapping services in client side APIs and delivered some as easy to consume REST/oData endpoints, but the functionality of those services is still limited and has not yet evolved to match the power of the native SharePoint Server API nor the native SharePoint Web Services.
When moving from an on-premise SharePoint to SharePoint Online web service clients that were previously written against SharePoint Web Services (like UserProfile.asmx or Lists.asmx) will stop working because the authentication model has changed. A web service client that previously used Active Directory accounts to access SharePoint will need to become “claims aware” to use SharePoint Online. This involves syncing active directory accounts up to the MS Online Active Directory and authenticating at the MS Online Security Token Service (STS) before accessing SharePoint.
We hit this problem where a client had built a set of jobs, utilities and components that request and update SharePoint through services which then broke when migrating to SharePoint Online. The solution to updating these clients is well covered by this blog by Wictor Wilén. What this involves is opening up the source code for each client and inserting the appropriate authentication code using the MSOnlineClaimsHelper to do get the authentication cookies before calling the service.
The problem is we really didn’t want to pick through someone else’s code and find all the places to insert the authentication code. Surely there is an easier way to inject this boilerplate code without having to recode all the clients? Turns out there is, if those clients are written using WCF. What we can do is write a WCF Client side behaviour to detect when authentication needs to be done, make the appropriate requests to MS Online STS, attach the cookies and then allow the SharePoint service request proceed as normal.
To use the ClaimsHelper, first set up the Uris of the SharePoint resources you want to access and the corresponding username/passwords using a CredentialCache and set it to the MsOnlineClaimsHelper.CredentialCache.
            CredentialCache credentialCache = new CredentialCache();            credentialCache.Add(_hostUri, “Basic”new NetworkCredential(“peter.reid@kloud.com.au”“blah”));            MsOnlineClaimsHelper.CredentialCache = credentialCache;Then there are two ways to use this library. Either manually request the cookies or attach to the outgoing request like this:
            UserProfile.UserProfileServiceSoapClient userProfile = new UserProfile.UserProfileServiceSoapClient(“UserProfileServiceSoap”, _hostUri + “_vti_bin/userprofileservice.asmx”);            using (new OperationContextScope(userProfile.InnerChannel))            {                _helper.AddAuthCookies(OperationContext.Current);                UserProfile.PropertyData[] data = userProfile.GetUserProfileByName(userName);                return Guid.Parse(GetPropertyValue(data, “UserProfile_GUID”));            }Or automatically do the same by adding the WCF client side behaviour like this:
 
    <behaviors>       <endpointBehaviors>         <behavior name="CookieBehavior">           <CookieBehaviorExtension/>         </behavior>       </endpointBehaviors>     </behaviors>     <extensions>       <behaviorExtensions>         <add name="CookieBehaviorExtension" type="ClaimsHelper.CookieBehaviourExtension, ClaimsHelper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>       </behaviorExtensions>     </extensions>     <client>       <endpoint behaviorConfiguration="CookieBehavior" binding="basicHttpBinding" bindingConfiguration="BasicBinding"                contract="UserProfile.UserProfileServiceSoap" name="UserProfileServiceSoap" />     </client>Which enables you to use a standard web service client call knowing that the authentication conversation is happening under the hood by the WCF client side behaviour.
            UserProfile.UserProfileServiceSoapClient userProfile
                    = new UserProfile.UserProfileServiceSoapClient("UserProfileServiceSoap", _hostUri + "_vti_bin/userprofileservice.asmx");
            UserProfile.PropertyData[] data = userProfile.GetUserProfileByName(userName);
            return Guid.Parse(GetPropertyValue(data, "UserProfile_GUID"));
Check out the code

No comments:

View Tenant (ULS) Logs in SharePoint Online using CSOM

Even though the classes exist in the CSOM, the Microsoft Office 365 Engineering team has confirmed that this is something which is not poss...