Skip to main content
Integration

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', 'application/json;odata=verbose');
reqWrite.setHeader('Content-Type', 'application/json;odata=verbose');
reqWrite.setHeader('X-RequestDigest',requestDigestXml);
reqWrite.setHeader('Cookie', cookie);
string writebody = '{ \'__metadata\': { \'type\': \'SP.Data.AccountTestListItem\' },\'Title\': \''+ AccountTitle +'\' }'; 
reqWrite.setBody(writebody);
reqWrite.setHeader('Content-Length', string.ValueOf(writebody.length()));
try
{    
resWrite = httpWrite.send(reqWrite);
}
catch(System.CalloutException e) 
{
System.debug('Callout error: '+ e);
}
}
}

The above apex class should be called by a trigger in Salesforce. But before that let’s understand how you can create an apex class in Salesforce.

You need to create a developer or production account with salesforce.com. After creating an account login to Salesforce.com as shown in the screen shot below.

1

Successful login will take you to a page as shown below,

2

In the left navigation, under build section open the develop menu and click on apex class as shown in the screen shot below.3

Apex class link will redirect you to the apex class library, in the apex class library click on the new link as shown in the screen shot below.

A new class will open in edit mode and you can write your class content and then save it with a meaning full name.

4

The source code given as apex class can be pasted in the editor and can be saved.

Once the class is created and saved with the given source code, the next step is to create a trigger in the sales force in order to trigger the creation of new account in SharePoint online, which would actually invoke the apex class. The trigger must be created on an entity, for this example, i have created the trigger on account entity in Salesforce. Let’s first understand, how you can create a trigger in Salesforce.

Once you have logged in to your Salesforce account with admin credentials, you need to go the build section and expand the develop menu and then click on apex trigger as shown in the screen shot below.

5

This would land you to the appex trigger library page. In the triggers library page click developer console as shown in the screen shot below

6

Click event on developer console will open the console window in new pop up. In the pop up window from the file menu select the triggers as shown in the screen shot below

7

The next screen would be as shown below, select the object or entity on which you need to create a trigger and give a meaning full name and save it.

8

With the trigger source code the trigger should look like as given below:

9

Save the trigger and create a new account entity in sales force. The prerequisite is you must have created a list in SharePoint online:

10

New button click event will open new account entity data capture form as shown in the screen shot below:

11

In this example, through trigger, Account name field is mapped with SharePoint list title field and hence whatever account name you would provide in the new account entity data capture form, the same will be created as an item in the SharePoint list.

For this example, I have created a list in SharePoint online with the name as “Account Test” as shown in the screen shot below.

12

You can see in the list which you would create a new item added with Title in the list as shown below.

13

Therefore, In order to have the Salesforce integration with SharePoint online, you need to keep two things in mind, one is remote authentication with SharePoint Online and the trigger in the Salesforce.

Ravish Verma

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.