SharePoint Online and Salesforce Integration

SharePoint online and Salesforce are two different cloud platforms, provided as “Software as a Service” from two different vendors.

SharePoint is a cloud based “Software as a Service” using which organizations can share content with colleagues, partners, and customers. SharePoint online also provides flexibility to access it from anywhere, i.e. home or office or wherever Internet connectivity is available and from any device, i.e. mobile/compact.

At the other end of the spectrum,  Salesforce is a cloud-based customer relationship management software solution for sales, service, marketing, collaboration, analytics and building reports.

Both the above can be considered as “Software as a Service” platforms.

In most business situations, there may be a use case, where business users would like to seamlessly obtain data from Salesforce on to SharePoint online, so that, the information can be collaborated from one single platform, instead of two different places.

In this blog, I will explain the concept and steps required to integrate Salesforce with SharePoint Online site, so that, information updated or created in Salesforce will, in real time, be updated and created in SharePoint online site.

When the question arises as to how to write data in SharePoint online, the first hurdle is to remotely authenticate the user against it, and in order to remotely authenticate the user, the best way available is REST api.

You need to make few rest calls to get the authentication piece as given below:

  • Get the security token
  • Get the access token
  • Get the request digest

The above rest call should be translated into an apex class which is supported by force.com

The first task is to get the SharePoint online security token, which can be obtained by posting XML as the request body to https://login.microsoftonline.com/extSTS.srf. In the XML you need to pass on account credentials which has at least contribute access.

The above request would fetch a response security token which is needed to get the access token.

In order to get the access token, again a rest call is required to be posted to the following URL with the security token as the request body:

https://yourdomain.sharepointonline.com/_forms/default.aspx?wa=wsignin1.0

The rest call with the request body including security token to the above URL would fetch a response, which would contain cookies and these cookies must be included in all the subsequent rest calls.

After the above operation you need to have the request digest. The request digest is obtained by posting the rest call along with the access token and the obtained cookies to the following URL:

https://yourdoamin.sharepointonline.com/_api/contextinfo.

The rest call that is posted to above URL will fetch the response along with the request digest. Please note that entire contents of the “FormDigestValue” tag would be required which includes the date time portion as well as time zone offset.

All the above steps have to be carried out in terms of a global apex class, and call the apex class with the trigger in sales force.

Apex class source code is as given below: 

global class SharePointOnlineWebserviceCallout{
 @future (callout=true)
 Public static Void GetAuthentication(string AccountTitle)
 {
 string body = '';
 string formattedCookie = '';
 string output = '';
 string cookie = '';
 string token = '';
 string username = 'account@sharepoint.com';
 string password = 'Password';
 string host = 'https://yourdoamin.sharepointonline.com';
 string tokenRequestXml ='<s:Envelope ' +
 'xmlns:s='http://www.w3.org/2003/05/soap-envelope' ' +
 'xmlns:a='http://www.w3.org/2005/08/addressing' ' +
 'xmlns:u='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'> ' +
 '<s:Header>' +
 '<a:Action s_mustUnderstand='1'>http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>' +
 '<a:ReplyTo> ' +
 '<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address> ' +
 '</a:ReplyTo>' +
 '<a:To s_mustUnderstand='1'>https://login.microsoftonline.com/extSTS.srf</a:To> ' +
 '<o:Security ' +
 's:mustUnderstand='1' ' +
 'xmlns:o='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'> ' +
 '<o:UsernameToken> ' +
 '<o:Username>' + username + '</o:Username>' +
 '<o:Password>' + password + '</o:Password>' +
 '</o:UsernameToken>' +
 '</o:Security>' +
 '</s:Header>' +
 '<s:Body>' +
 '<t:RequestSecurityToken xmlns_t='http://schemas.xmlsoap.org/ws/2005/02/trust'> ' +
 '<wsp:AppliesTo xmlns_wsp='http://schemas.xmlsoap.org/ws/2004/09/policy'> ' +
 '<a:EndpointReference> ' +
 ' <a:Address>' + host + '</a:Address> ' +
 '</a:EndpointReference> ' +
 '</wsp:AppliesTo> ' +
 ' <t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType> ' +
 '<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType> ' +
 ' <t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType> ' +
 '</t:RequestSecurityToken> ' +
 ' </s:Body> ' +
 '</s:Envelope>';

HttpRequest reqBinaryToken = new HttpRequest();
reqBinaryToken.setEndpoint(‘https://login.microsoftonline.com/extSTS.srf’);
reqBinaryToken.setMethod(‘POST’);
reqBinaryToken.setbody(tokenRequestXml);
reqBinaryToken.setHeader(‘Content-Length’,String.valueof(tokenRequestXml.length()));
reqBinaryToken.setTimeout(60000);

HttpResponse responseBinaryToken = new HttpResponse();
Http httpBinaryToken = new Http();
responseBinaryToken = httpBinaryToken.send(reqBinaryToken);
string xmlContent = responseBinaryToken.getBody();
Dom.Document doc = responseBinaryToken.getBodyDocument();
Dom.XMLNode address = doc.getRootElement();
//XmlStreamReader reader = new XmlStreamReader(responseBinaryToken.getBody());
string outxmlstring = String.valueof(doc.getRootElement().getName());//gives you root element Name

XmlStreamReader reader = new XmlStreamReader(responseBinaryToken.getBody());
while(reader.hasNext()) {
if (reader.getEventType() == XmlTag.START_ELEMENT && reader.getLocalName()== ‘BinarySecurityToken’) {
reader.next();
if(reader.hasNext()){
if(reader.getEventType() == XmlTag.CHARACTERS){
token = reader.getText();
token += ‘&p=’;
}
}
}
reader.next();
}

HttpRequest requestCookie = new HttpRequest();
requestCookie.setEndpoint(‘https://yourdoamin.sharepointonline.com/_forms/default.aspx?wa=wsignin1.0’);
requestCookie.setHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);
requestCookie.setHeader(‘User-Agent’,’Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)’);
requestCookie.setMethod(‘POST’);
requestCookie.setBody(token);
requestCookie.setHeader(‘Content-Length’,String.valueof(token.length()));

HttpResponse responseCookie = new HttpResponse();
Http httpCookie = new Http();
responseCookie = httpCookie.send(requestCookie);
string location = responseCookie.getHeader(‘Location’);

if(responseCookie.getStatus() == ‘MovedPermanently’){
HttpRequest reqMovedPermanently = new HttpRequest();
reqMovedPermanently.setHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);
reqMovedPermanently.setMethod(‘POST’);
reqMovedPermanently.setEndpoint(‘https://yourdoamin.sharepointonline.com/_forms/default.aspx?wa=wsignin1.0’);
reqMovedPermanently.setBody(token);
reqMovedPermanently.setHeader(‘Content-Length’,String.valueof(token.length()));
reqMovedPermanently.setHeader(‘Location’, location);
reqMovedPermanently.setHeader(‘User-Agent’,’Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)’);
HttpResponse responseMovedPermanently = new HttpResponse();
Http httpMovedPermanently = new Http();
responseMovedPermanently = httpMovedPermanently.send(reqMovedPermanently);
cookie = responseMovedPermanently.getHeader(‘Set-Cookie’);
}
else
{
cookie = responseCookie.getHeader(‘Set-Cookie’);
}

HttpRequest requestDigest = new HttpRequest();
requestDigest.setEndpoint(‘https://yourdoamin.sharepointonline.com/_api/contextinfo’);
requestDigest.setMethod(‘POST’);
requestDigest.setBody(body);
requestDigest.setHeader(‘Content-Length’,String.valueof(body.length()));
requestDigest.setHeader(‘Accept’,’application/json;odata=verbose’);
requestDigest.setHeader(‘Content-Type’,’application/json;odata=verbose’);
requestDigest.setHeader(‘Cookie’,cookie);

Http httpRequestDigest = new Http();
HttpResponse responseRequestDigest = new HttpResponse();
responseRequestDigest = httpRequestDigest.send(requestDigest);
string requestDigestValue = responseRequestDigest.toString();
string xmlContentRequestDigest = responseRequestDigest.getBody();

Integer index1 = xmlContentRequestDigest.indexOf(‘”FormDigestValue”:”‘);

Integer index2 = ‘”FormDigestValue”:”‘.length();

string contentRequestDigest = xmlContentRequestDigest.Substring(index1 + index2);

string requestDigestXml = contentRequestDigest.split(‘”‘)[0];

HttpRequest reqWrite = new HttpRequest();
HttpResponse resWrite = new HttpResponse();
Http httpWrite = new Http();
reqWrite.setEndpoint(‘https://yourdoamin.sharepointonline.com/_api/web/lists/GetByTitle(‘AccountTest’)/items’);
reqWrite.setMethod(‘POST’);
reqWrite.setCompressed(false);
reqWrite.setHeader(‘Accept’

Ravish Verma

Ravish works as Senior Technical Lead with Trigent Software. He has extensive experience in Design and Development of Enterprise Applications based on SharePoint Online, SharePoint® 2013, SharePoint® 2010 and SharePoint® 2007. He comes with demonstrated analytical skills along with expertise in business communication and relationship management. Ravish is a leader with strong analytical, problem solving abilities and track record of forging business partnerships.