Implementing custom document location logic with a plugin

By | April 10, 2019

In one of the previous posts I used Microsoft Flow to create folders in SharePoint whenever a record is created in Dynamics/CDS. That was not extremely straightforward to me, but, at least, I did not have to fight with the authentication.

But, having done this, we’ve figured that we should still try a plugin instead (after all, a plugin could do everything synchronously, so it might be less confusing for Dynamics users).

This turned out to be a much more monumental task since we did not really have a lot of experience with SharePoint API-s etc.

This post is a result of those experiments. It’s not meant to explain all the intricacies of how SharePoint works, how OAuth works, etc. Basically, it’s going to be a step-by-step walkthrough, and, in the end, there is going to be sample source code.

Just to give you an idea of how it’s going to work, here is a quick diagram:

image

The main problem there turned out to be getting that token. There is a solution that Scott Durow developed some time ago:

https://code.msdn.microsoft.com/SharePoint-Integration-c5f21604

But, as it turned out, that one is using legacy office 365 authentication, and it can now be disabled through the conditional access policy:

https://www.itaintboring.com/dynamics-crm/office365-authentication-for-the-sdk-xrmtoolbox/

Of course that policy has been applied in our tenant.. Murphy’s law in action, I guess.

So we needed a different solution.

There are a few links which helped a great deal, so I’ll just provide them here for your reference:

There were a couple of key concepts I had to realize while reading through those:

  • SharePoint is not using Azure AD Application registrations for OAuth – there is a separate application registration process, and there is a separate token service
  • When registering an app in SharePoint, we are getting a completely new security principal, as the second link above explains: “After you’ve registered your add-in, it is a security principal and has an identity just as users and groups do” . You can also see it on the screenshot below if you look at the “Modified By” column:

clip_image002

Either way, with all that said, we need to go over a few steps:

  • Register an add-in
  • Create the code that gets the token and calls Sharepoint REST API
  • Write a plugin that is using the same code to create folders in Sharepoint and document locations in Dynamics as needed

Step 1: Registering an add-in

I’ve registered the add-in using <site>/_layouts/15/AppRegNew.aspx page as described here:

https://docs.microsoft.com/en-us/sharepoint/dev/sp-add-ins/register-sharepoint-add-ins

Keep in mind that, later on, you’ll be giving permissions to this add-in, so, depending on where you have installed it(site collection / site), you might be able to limit those permissions to the specific site.

image

Make sure to copy the client secret and the client id – you’ll need those later.

***********************************************************************************************

Also, as strange as it is, there seem to be no easy way to browse through the add-ins registered this way, but you can use PowerShell as described here:

https://docs.microsoft.com/en-us/sharepoint/dev/sp-add-ins/replace-an-expiring-client-secret-in-a-sharepoint-add-in

First of all, this link mentions something that you may want to keep in mind:

Client secrets for SharePoint Add-ins that are registered by using the AppRegNew.aspx page expire after one year

Not sure how exactly that is supposed to be managed, but let’s leave it for later (have a feeling this is a common problem, so either there is a common solution somewhere, or this is a well-known pain, so a reminder has to be implemented and some manual steps have to be taken periodically)

Either way, to get Connect-MsoService working, also make sure to follow the instructions here:

https://docs.microsoft.com/en-us/office365/enterprise/powershell/connect-to-office-365-powershell

***********************************************************************************************

Now that we have the add-in, it’s time for

Step 2: Setting up add-in permissions

Have a look at the article below:

https://docs.microsoft.com/en-us/sharepoint/dev/sp-add-ins/add-in-permissions-in-sharepoint

For the add-in we are creating, we will need read/write permissions on the site, so here we go:

Permissions for the next screenshot:

<AppPermissionRequests AllowAppOnlyPolicy=”true”>

<AppPermissionRequest Scope=”http://sharepoint/content/sitecollection” Right=”FullControl” />

</AppPermissionRequests>

Why is it for the sitecollection? Not 100% sure.. I would think tenant should work, but it did not (kept getting “access denied” errors down below when trying to run api queries)

Navigate to the <site_url>/_layouts/15/appinv.aspx

Paste App Id (copied from Step 1) and lookup the app, then paste permissions from above, then click “Create”

image

Step 3: Creating a Plugin

For this and the following steps, you will need to find out your sharepoint tenant id. Follow the steps here:

https://stackoverflow.com/questions/38097668/how-do-i-find-the-tenant-id-of-my-sharepoint-online-account

In short, open this url:

http:// <SharePointWebsite> /_layouts/15/AppPrincipals.aspx

You will see tenant id there:

image

By this moment you should have the following 4 parameters:

  • Client id
  • Client Key
  • Tenant Id
  • And you should definitely know your sharepoint url

 

You will find the source code for the first version of the plugin on GitHub here:

https://github.com/ashlega/ItAintBoring.SharePointPlugin

It definitely deserves a separate post, and there are a few things to do there to improve the code/make it more flexible, but, for now, here is how it works:

  • Build the solution
  • Register the plugin on create of the Lead entity (could be any other document-enabled entity), post-operation, synchronous
  • Add secure configuration to the step

 

image

For the secure configuration, use the following XML:

<settings>
<clientId>YOUR CLIENT ID</clientId>
<clientKey>YOUR KEY</clientKey>
<tenantId>YOUR TENANT ID</tenantId>
<siteRoot>treecatsoftware.sharepoint.com(REPLACE WITH YOURS)</siteRoot>
</settings>

Now prepare SharePoint and Dynamics:

  • Create a document library in Sharepoint, call it “DynamicsDocs” (right in the root)
  • Assuming “Default Site” refers to the SharePoint root, create a document location in Dynamics like this:

 

image

With that done, if you create a lead in Dynamics, here is what will happen:

  • The plugin will create new folder under DynamicsDocs (using new lead ID for the folder name)
  • And it will create a document location in Dynamics to link that folder to the lead entity

 

Hope I’ll be able to write another post soon to explain the plugin in more details, and, also, to add a few improvements..

2 thoughts on “Implementing custom document location logic with a plugin

  1. Shidin Haridas

    Hey Alex,

    Couple of questions:
    1. The sync plugin has to authenticate with SP and create the folders. Doesn’t this operation exceed the plugin execution time limits?
    (We faced the time-out issue in one of our implementations and ended up using Azure Functions and web-hooks for the SharePoint code)

    2. For the SharePoint operations, are you using any SharePoint specific DLLs such as the Microsoft.SharePoint.Client or SharePointPnP.Client?

    Reply
    1. Alex Shlega Post author

      Hi Shidin, for #2 – the plugin is using SharePoint rest API, essentially from scratch (we don’t need much to create a folder), so there are no SharePoint libraries involved. It’s all done through the HttpClient. #1 – we’ll have to see how it works out. Getting a token does not take long, creating a single folder (that’s the purpose of the plugin) does not take long. How it holds under load(data migrations and/or data imports) is a good question. Although, I am wondering if we’d be able to use this approach to basically intercept default documentlocation “flow”(in which case we would not have to create documetn locations “on create”).. technically we probably could intercept document location creation in a different plugin, delete default sharepoint folder created for that location and create ours instead..

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *