This is the era of cloud. Everything everywhere is connected with each other via cloud hosted web services and people can access these services from anywhere in globe, anytime. Such are the powers of cloud. But is everything really connected as is expected?
Not every cloud based service can be connected with every other service, but fortunately most popular Apps can be integrated. And so can Salesforce and Microsoft SharePoint be integrated – two of the most popular Software-as-a-Service (SaaS) products.
However it is not that simple. In this post we are going to discuss different ways by which you can integrate Salesforce with SharePoint. But first let us identify why would you even need to integrate the two?
Why Salesforce SharePoint Integration?
SharePoint is a very robust content management and document management platform used by all kinds of companies, mainly for storing business related documents and content. It is mostly used as a secure document repository for intranet portals, websites, cloud based services, and of course as independent repository as well. However it is mostly used by businesses using other Microsoft Office products like Excel and Word to create documents. Now since they belong to the same product family, the created documents can be easily exported to SharePoint.
Salesforce on the other hand is a huge SaaS platform used by millions of companies to manage their business processes. It mainly started as a Customer Relationship Management Platform but thanks to its versatility regarding integrations and extensions along with a boost in its ever-growing list of features, it has evolved into a complete sales, marketing and support business process management platform and can be used for many many kind of analysis for businesses.
However it was never known for its document storage capabilities. You can store documents there but it charges quite high fees for storage and is not as robust as Microsoft 365 in this aspect.
So why not simply integrate the two? Most companies having a Microsoft 365 account don’t want to spend more on Salesforce storage. So integration remains the best option.
Salesforce SharePoint Integration Using Microsoft Azure Service
There are a number of ways you can integrate SharePoint with Salesforce. However Microsoft has not released any API to facilitate direct Salesforce SharePoint interactions so we need to involve a third-party adapter or service. The different ways are:
- Integrating using a third party system installed adapter
- Integrating using a Microsoft Azure hosted service.
- Integrating using a third party integration service.
The first way involves building a third-party adapter that had to be physically installed on a computer system and therefore severely limits the cloud based capabilities. The third way involves using a paid or even free integration service, it is easy to use but it is not as flexible as a custom adapter and may prove to be a security risk. Moreover the main point of integration was to save cost so paying to save cost needs to properly analyzed.
So the best cloud integration method left is to use a Microsoft Azure hosted service to integrate your Salesforce and SharePoint.
This method involves multiple steps
- Step 1: Salesforce sends authentication request to the Adapter.
- Step 2: The Adapter passes on the request to the SharePoint.
- Step 3: SharePoint authenticates the information and passes on a security token for further use.
- Step 4: The adapter receives the token and passes on the token to Salesforce.
- Step 5: Using the token as an authentication key, Salesforce then send request to view specific or all accessible files and folders.
- Step 6: The Adapter passes on the request along with the token and receives an output which it again passes on to the Salesforce installation.
- Step 7: Either the token expires and the process is repeated again, or using the same token more requests are sent and received.
It seems simple when I present the steps like this but in reality if the coder is experienced and careful it’s just as simple.
How Salesforce Performs Step 1
The main point for cloud based integration is to host a running service on Microsoft’s cloud app platform Azure, and leveraging it to interact with SharePoint. Since the service is hosted on a cloud platform, we usually access it via web-based URL. So our methods from Salesforce side to request authentication token look something like this:
public static String getToken(){ String token; if(!Test.isRunningTest()){ token = SharePointAPIUtility.SharePointAPIGet('','[email protected]','TestingPassword'); } system.debug('token>>> '+token); if(token != null){ return EncodingUtil.urlEncode(token.replaceAll('"',''), 'UTF-8'); } return null; } public static String SharePointAPIGet(String endpointUrl,String username, String password){ try{ HttpRequest httpRequestObject = new HttpRequest(); httpRequestObject.setEndPoint(endpointUrl); httpRequestObject.setmethod('GET'); Blob headerValue = Blob.valueOf(username + ':' + password); String authorizationHeader = 'BASIC ' + EncodingUtil.base64Encode(headerValue); httpRequestObject.setHeader('Authorization', authorizationHeader); httpRequestObject.setTimeout(120000); system.debug('httpRequestObject>> '+httpRequestObject); Http http = new Http(); HttpResponse httpResponse ; if(!test.isRunningTest()) httpResponse = http.send(httpRequestObject); if(httpResponse != null && httpResponse.getStatus() == 'OK' && httpResponse.getStatusCode() == 200){ system.debug('httpResponse.getBody();>>>>'+httpResponse.getBody()+'httpResponse.getBody();>>>>'); return httpResponse.getBody(); }else if(httpResponse != null){ return 'SharePoint Server Error: Status '+ httpResponse.getStatus()+' Status Code '+ httpResponse.getStatusCode() +' Body '+httpResponse.getBody(); } }catch(CalloutException ce){ throw ce; }catch(Exception ex){ throw ex; } return null; }
This code hits the Azure service using the URL and receives the authentication token which the Azure service sends.
We will come to the steps 2,3 and 4 right after the 5th:
How Salesforce Performs Step 5
Once Salesforce has authentication token, it uses that to request files and folders from the adapter. Once again it uses the Azure service URL to hit the service.
Here’s a method to request files and a method to request folders
public static List<String> getAllFolders(SharePoint365APIParser objSharePoint365APIParser){ try{ list<String> objFolders = new list<String>(); if(objSharePoint365APIParser.folders != null && objSharePoint365APIParser.folders.size()>0)//null check for(SharePoint365APIParser.folders sp:objSharePoint365APIParser.folders){ objFolders.add(sp.name); } return objFolders; }catch(Exception ex){ throw ex; } return null; } public static List<String> getFilesByFolder(String folderName, SharePoint365APIParser objSharePoint365APIParser){ //if(!test.isRunningTest()){ try{ if(objSharePoint365APIParser.folders != null && objSharePoint365APIParser.folders.size()>0) for(SharePoint365APIParser.folders sp:objSharePoint365APIParser.folders){ if(sp.name.equalsIgnoreCase(folderName)){ if(sp.files.size() > 0){ return sp.files; }else{ return new list<String>(); } } } }catch(Exception ex){ throw ex; } //}//end running test loop return null; }
How Azure Performs Step 2, 3, and 4
Once Salesforce has sent the request for authentication token, here’s how Azure platform service authenticates login.
[HttpPost] public bool Login(string email, string password) { //throw new Exception("This is error!!"); bool validateLogin = false; List<string> MessageList = new List<string>(); //string decryptedPassword = Encryption.Decrypt(encryptedPassword); if (email == ConfigurationManager.AppSettings["Email"] && password == ConfigurationManager.AppSettings["Password"]) { string authInfo = email + ":" + password; authInfo = Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(authInfo)); //authInfo = Encryption.Encrypt(authInfo); System.Web.HttpContext.Current.Response.AppendHeader("Authorization", "Basic " + authInfo); // Insert User Token MessageList.Add("Login Successful"); validateLogin = true; } else { MessageList.Add("Invalid Username Or Password"); } return validateLogin; }
How Azure service handles Step 6
Now that Salesforce has authentication token and is logged in on SharePoint, here’s how our Azure service parses the request for file and folder lists.
[AuthorizeWebAPI()] [HttpGet] public Folders GetResourceData() { Folders fld = new Folders(); try { using (ClientContext clientContext = new ClientContext("")) { SecureString passWord = new SecureString(); foreach (char c in "TestPassword".ToCharArray()) passWord.AppendChar(c); clientContext.Credentials = new SharePointOnlineCredentials("[email protected]", passWord); Web rootweb = clientContext.Web; var folders = rootweb.GetFolderByServerRelativeUrl("/Resources").Folders; string pString = @"Resources"; clientContext.Load(folders); clientContext.ExecuteQuery(); fld.folders = new List<Folders>(); fld.name = "Resources"; foreach (Microsoft.SharePoint.Client.Folder myFolder in folders) { fld.folders.Add(GetFoldersAndFiles(myFolder, clientContext, pString)); } } } catch (Exception) { fld.name = "Some error happened."; } return fld; } private Folders GetFoldersAndFiles(Microsoft.SharePoint.Client.Folder mainFolder, ClientContext clientContext, string pathString) { Folders fldr = new Folders(); List<string> fls = new List<string>(); fldr.folders = new List<Folders>(); clientContext.Load(mainFolder, k => k.Files, k => k.Folders); clientContext.ExecuteQuery(); foreach (var folder in mainFolder.Folders) { string folderPath = string.Format(@"{0}{1}", pathString, folder.Name); if (folder.Name != "Forms") fldr.folders.Add(GetFoldersAndFiles(folder, clientContext, folderPath)); } foreach (var file in mainFolder.Files) { fls.Add(file.Name); } fldr.files = fls; if (mainFolder.Name != "Forms") fldr.name = mainFolder.Name; return fldr; }
As you may see, we have saved all our content on SharePoint as resources and the service retrieves the data from that resource folder.
How To Display SharePoint Files
Now the integration won’t be as effective if we are not able to display the retrieved files somewhere. In our experience it is best to retrieve files using Salesforce and create a separate Visualforce page to display the retrieved files. Using SharePoint’s inbuilt features it is very easy to display retrieved files. You just have to embed a single line of code in your Visualforce page.
Embedded office control
<embed src="https://view.officeapps.live.com/op/view.aspx?src=filepath%2FWebsite%20Requirements.docx" width=800px height=500px></embed>
To retrieve single file you would also need your Azure service. That code would look something like this:
public ActionResult DisplayFile(string filePath, string token) { try { var decrypt = new Encryption(); DateTime dt = new DateTime(); if (DateTime.TryParse(decrypt.Decrypt(token), out dt)) { if (DateTime.UtcNow.Subtract(new TimeSpan(0, 3, 0)) < dt && DateTime.UtcNow.Add(new TimeSpan(0, 3, 0)) > dt) { var filename = Path.GetFileName(filePath); var dirName = Path.GetDirectoryName(filePath); var contentType = "application/octet-stream"; var localFilePath = Server.MapPath("~/SharedDownloads/"); var localFileName = DateTime.Now.ToString("yyyyMMddHHmmssfff") + "_" + filename; var wholePath = Path.Combine(localFilePath, localFileName); ValuesController api = new ValuesController(); (from f in new DirectoryInfo(localFilePath).GetFiles() where f.CreationTime < DateTime.Now.Subtract(TimeSpan.FromMinutes(30)) select f).ToList() .ForEach(f => f.Delete()); using (ClientContext clientContext = new ClientContext("")) { SecureString passWord = new SecureString(); foreach (char c in "TestPassword".ToCharArray()) passWord.AppendChar(c); clientContext.Credentials = new SharePointOnlineCredentials("[email protected]", passWord); Web rootweb = clientContext.Web; Microsoft.SharePoint.Client.File file = rootweb.GetFileByServerRelativeUrl(filePath); clientContext.Load(file); clientContext.ExecuteQuery(); contentType = GetMimeType(Path.GetExtension(filePath)); api.DownloadFile(clientContext, filePath, localFilePath, localFileName); } return View(new FileModel { FileName = "/SharedDownloads/" + localFileName, ContentType = contentType }); } } } catch (Exception) { return View(new FileModel { FileName = "Error" }); } return View(new FileModel { FileName = "Error" }); }
Using Salesforce Files Connect
Salesforce and Microsoft, in an obvious strategy of mutual benefit went into an extended partnership. On December 17 Salesforce launched its new features via Salesforce Files Connect. It was released after much research and is touted as a method to integrate Microsoft 365 products as well as Microsoft OneDrive. For CRM license holders this service is available for free in limited capacity of course, and can be used to integrate Salesforce with SharePoint directly. But since it’s a new service it’s still not tested for the most optimum performance and security standards by third party users. We here at Algoworks have an immense experience with such third party service integration services- both system based and Azure service based. We can safely assume that in the near future Files Connect would be the dominant way to integrate both SaaS platforms.