Using MIP SDK in SharePoint – II

This post is in continuation with how to use MIP SDK in C#. Please go through it first to cover some basic concepts like, setting up your system, nuget required for MIP and registering Azure AD app which will be used in the code below too.

My case scenario was to analyze a protected file present in SharePoint Document Library and set/remove protection on it depending on the contents of the document. In case you are not aware, we can use Azure Information Protection or Unified Labeling in SharePoint too. It’s pretty straight-forward and more details can be found here.

In comparison to the code I uploaded on git, there are few basic changes for using MIP SDK in Provider Hosted add-ins. Instead of relying on file path, we will use file stream from SharePoint and similarly, upload that stream back to SharePoint. I am assuming that you all are aware of provider hosted add-ins and have gone through the part one of this post. I am listing the changes below while rest of the stuff remains the same.

  1. Create a provider hosted add-in using Visual Studio. I have used SharePoint Online and MVC template for my work
  2. In AppManifest.xml give proper permission to access libraries of your target site collection
  3. Now coming to HomeController, InvokeMIP method, the first difference is how will we get tenant id of our host web. Instead of finding it in Claims, we will get it using TokenHelper’s method GetRealmFromTargetUrl
  4. Apart from this, we will create SharePoint context to get file stream of the uploaded file where we need to perform MIP operations
  5. Using this stream, MIP file handler will be created
  6. The output will be collected in memory stream
  7. Output Stream will be used to upload the changed document back to SharePoint (For more details on how to upload large files in provider hosted add-in, check this post here)

The complete code will look like below:


private void InvokeMIP()
{
//this client id is for Azure AD app and NOT of SharePoint app
private static readonly string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static readonly string appName = ConfigurationManager.AppSettings["app:Name"];
private static readonly string appVersion = ConfigurationManager.AppSettings["app:Version"];
private static readonly string mipData = ConfigurationManager.AppSettings["MipData"];
private readonly string mipPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, mipData);
try
{
SharePointContext spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
Uri sharepointUrl = new Uri(spContext.SPHostUrl.AbsoluteUri.ToString());
//fetch tenant id to be used in getting access token
string tenantId = TokenHelper.GetRealmFromTargetUrl(sharepointUrl).ToString();
// Set path to bins folder.
var path = Path.Combine(
Directory.GetParent(Path.GetDirectoryName(new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath)).FullName,
Environment.Is64BitProcess ? "bin\\x64" : "bin\\x86");
MIP.Initialize(MipComponent.File, path);
ApplicationInfo appInfo = new ApplicationInfo()
{
ApplicationId = clientId,
ApplicationName = appName,
ApplicationVersion = appVersion
};
AuthDelegateImplementation authDelegate = new AuthDelegateImplementation(appInfo, tenantId);
var profileSettings = new FileProfileSettings(mipPath, false, authDelegate, new ConsentDelegateImplementation(), appInfo, LogLevel.Trace);
//create MIP File Profile
var fileProfile = Task.Run(async () => await MIP.LoadFileProfileAsync(profileSettings)).Result;
//create MIP Engine and add it to the file profile
var engineSettings = new FileEngineSettings("", "", "en-US");
engineSettings.Identity = new Identity("admin@tenant.com"); //important to paas a valid admin account here
var fileEngine = Task.Run(async () => await fileProfile.AddEngineAsync(engineSettings)).Result;
//client context to get file stream
using (var clientContext = spContext.CreateUserClientContextForSPHost())
{
if (clientContext != null)
{
var list = clientContext.Web.Lists.GetByTitle("Documents");
clientContext.Load(list, i => i.RootFolder);
clientContext.ExecuteQuery();
var listItem = list.GetItemById(1);
clientContext.Load(listItem, l => l.File, l => l.File.ServerRelativeUrl);
var fileData = listItem.File.OpenBinaryStream();
clientContext.ExecuteQuery();
if (fileData.Value != null)
{
var fileStream = fileData.Value;
//create file handler with the stream from SharePoint
var handler = Task.Run(async () => await fileEngine.CreateFileHandlerAsync(fileStream, listItem.File.ServerRelativeUrl, true)).Result;
//if needed, can check the existing labels and protection details using below two lines
var labelDetails = handler.Label;
var protectionDetails = handler.Protection;
LabelingOptions labelingOptions = new LabelingOptions()
{
AssignmentMethod = AssignmentMethod.Privileged, //because I am removing a high priority label
IsDowngradeJustified = true,
JustificationMessage = "Lowering label"
};
handler.DeleteLabel(labelingOptions);
//output stream where new file will be stored
Stream outputStream = new MemoryStream();
var result = Task.Run(async () => await handler.CommitAsync(outputStream)).Result;
//This is neccessary else you will get following error
//Specified argument was out of the range of valid values.\r\nParameter name: bytesToCopy
outputStream.Position = 0;
//You can create a new file handler using output stream here
//and use it to apply different label using newhandler.SetLabel() method
//and then upload it to SharePoint too
FileCreationInformation decryptedFile = new FileCreationInformation();
decryptedFile.ContentStream = outputStream;
decryptedFile.Url = "decrypted.docx"; //change this according to your need
decryptedFile.Overwrite = true;
var uploadedFile = list.RootFolder.Files.Add(decryptedFile);
clientContext.Load(uploadedFile);
clientContext.ExecuteQuery();
}
}
}
}
catch(Exception ex)
{
}
}

Make sure you have registered Azure AD app with proper permissions and your SharePoint App has correct permissions too.

P.S. Please note that MIP SDK does not support content marking (watermark, header, footer). You can apply a label with watermark but it wont be reflected until you open the document and save it in office again. More details here

Happy Coding!

Update November 9, 2019:

Now you can enable sensitivity labels for file present in OneDrive and SharePoint. The feature comes with some new capabilities and some limitations and is currently in public preview. Click here to learn more about this.

Working with C# MIP SDK – I

Recently I got a chance to work with the MIP SDK which is the unification of Microsoft’s classification, labeling, and protection services. Now is the time for data, and its security is paramount for everyone. Microsoft provides some amazing tools to protect our data tenant wide (if you are using O365 Online) or across your farms (in case of on-premises). If you are not aware of the core concepts, I would urge you to read the following links, before jumping to the SDKs.

  1. Azure Information Protection
  2. Office 365 Security and Compliance

The MIP SDK helps you to create custom third-party apps to create, apply, remove labels from your files. It might come handy in cases when you, as a super admin wants to access a protected file, apply labels based on some sensitivity information or even remove labels to check the data. These SDKs are built in C++ and MS provides a C# wrapper over it. There are some good samples provided by Microsoft and they cover a lot of things. But my requirement was bit different. I wanted create a multi-tenant SAAS application which can access these labels. Not only this, it was going to be like a daemon service with no user interaction and hence I needed app-only permissions. Therefore, I used client credential flow to implement this.

Coming back to the challenges I faced:

  1. It took me some time to set up my machine for development
  2. Not much documentation is available for C# and hence I took a lot of time to understand it
  3. The github samples and the test code in the documentation are different. I have to go with code snippets provided in documentation and figure out the rest
  4. Spent some time exploring all the permissions needed and how will they work together for various operations

Here are the assumptions I took from my side:

  1. You have gone through the concepts of File Profiles and File Engines
  2. You already have idea of registering multi-tenant Azure AD app and how it works
  3. You have a basic idea of OAuth and various authorization flow it uses, like client credentials flow

Now coming to the setup of your machine, the exhaustive list could be found here. I am covering the things I did to set up my Windows 10 environment.

  1. Created a demo account which has AIP enabled for trial
  2. Configured few sensitivity labels with various settings in O365 Security and Compliance Center
  3. Make sure your Windows 10 has version 1709 or later
  4. My machine does not have “Developer Mode” enabled but it works
  5. Installed Universal Windows Platform development in VS 2017, which took like 2 hours
  6. Downloaded and installed MIP SDK for Windows
  7. And you are done!!!!!

As our development environment is ready, lets fire up VS (I am using 2017)

  1. Create new .Net Web Application -> Choose MVC Template -> Change Authentication to “Work or School Accounts” -> “Cloud – Multiple Organizations”. Provide relevant domain and create a new project
  2. This will automatically create a registration in Azure AD with your project name. Login to portal -> Azure Active Directory -> App Registrations and search for the app you created
  3. For demo purpose I am using default localhost Redirect URI created by VS
  4. Navigate to “API permissions” tab and grant the following permissions. Make sure to click on “Grant admin consent” so that permissions are authorized by admin. Notice that all are application permission, except for MS Graph which is used for login
  5. Navigate to “Certificates and secrets” tab and create new client secret. Remember to copy and save it in web.config. This is not a secure practice and in production environment you should use Key Vault to store it securely
  6. Move to the project created in VS and update your web.config with following entries
  7. Install following Nuget in the project: Microsoft.InformationProtection.File and Microsoft.IdentityModel.Clients.ActiveDirectory
  8. That’s it!

You can find the complete source code at my github repo. Below are few issues I faced and how I solved it:

  1. Load Library failed for mip_dotnet.dll : To fix this, you need to provide the path of dll from the app folder. That’s why in HomeController line 41 you can see I have initialized MIP by providing the path
    MIP.Initialize(MipComponent.File, path);
  2. Also make sure to provide proper path while creating File Profile at line 54 as this is the place under which logging, telemetry, and other persistent state is stored.
    var profileSettings = new FileProfileSettings(mipPath, false, authDelegate, new ConsentDelegateImplementation(), appInfo, LogLevel.Trace);
  3. Make sure “ID Tokens” is enabled in AD registered app

I hope this helps in getting started with MIP SDK in C#. I have updated the code to remove protection from a file, you can try other similar operations.

In Part two we will go through using MIP SDK with SharePoint files. To make stuff more interesting, we will implement it in SharePoint Provider Hosted Add-In.

Happy Coding!

Update November 9, 2019:

Now you can use sensitivity labels with MS Teams, O365 and SharePoint Sites. This feature is in public preview. Click here to learn more about this.