Using the SLPS SaaS SDK in Azure (KB18)

To license SaaS application on Azure you will need to use the SLP SaaS SDK. As of SLP v3.1.1917 this SDK is shipped automatically as part of the vendor permutation. If you have a previous version you will need to update your permutation, download it and extract the necessary components.

This document describes the actions necessary to use the SaaS SDK in default mode  with MVC applications on Azure.

Overview

To use the SLP SaaS SDK with Windows Azure you will need to do some initial configuration and set up:

  • Update your permutation and extract components
  • Create product and associated feature definitions in Online portal
  • Referene the SDK files in your application
  • Implement ILicensePartition Interface
  • Configure your Azure storage Account.

Then you need to implement the actual license checks in your code by

  • Providing a mechanism to activate licenses (using ActivationKeys)
  • Loading licenses into the CurrentPrincipal
  • Adding license authorisation, either programmatically or by using LicenseAuthorize attribute.

Configuration and Setup

Update your permutation to the latest build

The SLPS Saas SDK is shipped as part of your permutation. You therefore need to update your permutation to avail of the functionality.

  • Login srv.softwarepotential.com
  • Navigate to Accounts|Manage Permutations
  • Select your permutation and click the “Update” button. It will take a few minutes to regenerate your permutation. You’ll know when it’s complete when you click “Refresh” and the Status changes to “Done”
  • The Version number of the Permutation should be at least 3.1.1917
  • Download the associated Code Protector and install (you’ll need to uninstall any previous versions of Code Protector)
  • Download the associated Permutation
  • Start Code Protector and install the downloaded permutation following the usual procedure. This will unpack the necessary Saas SDK files into your Permutations folders.

The Saas SDK is a set of DLLs that expose licensing functionality within your Azure web application. The SDK uses your SLPS Permutation and Azure Storage Account to store licenses and enforce license limitations.

A certain amount of build configuration is required within your .Net project to enable the functionality exposed by the SDK. Additionally there are a number of dependencies that should be installed.

Create a Product and Version on the SLP Online portal

Your application will be using SLPS licensing. In this paradigm, licenses are associated with a Permutation and with a Product Name and Version. You have already enabled your project to be associated with the correct Permutation DLL above. Later we will associate your application with a product name and version, but first you need to declare the Product Name and Version on the SLP Online portal so that you can issue licences that are used in your application.

This name and version will be used in application start up code used by the SLPS SDK (more on that below).

You will need to create Features for the product which will be used later when implementing license checks in your code. To do this:

  • On Manage Products page select the product created in the last step
  • Click "Edit Product"
  • Enter a Name and optional Description for each feature to be licensed, clicking the '+' symbol to save each feature definition.

You can now leave the SLP Online portal.

Dependencies

The following additional frameworks must be installed for the proper operation of the Saas SDK:

Restart all Visual Studio instances after installation.

Reference the Saas SDK files in your Web Application

Once the dependencies have been installed, you need to reference the Saas SDK DLLs in your application. (In the future, we will provide the SDK DLLs as NuGet packages which will make the following steps easier).

  • Within Visual Studio, unload your web application project and edit the .csproj file
  • Add the following lines near the bottom of the .csproj file (just after the existing import of WebApplication.targets):
<PropertyGroup>
<SlpsRuntimePermutationId>bcfd56a1-a753-485a-b99e-25fe6b749225</SlpsRuntimePermutationId>
<SlpsRuntimeVariant>Saas</SlpsRuntimeVariant>
</PropertyGroup>
<Import Project="$(SlpsSdkPath)\Slps.Runtime.References.targets" />

You will need to replace the above Permutation identifier with your own, which should match up with the ID in the permutations folder of your code protector installation folder - C:\Program Files (x86)\InishTech SLP Code Protector\Permutations.

Note that the “Permutation Short Code” is in fact the first 5 characters of the entire permutation string. We’ll need this Short Code later.

Implement ILicensePartition interface

Standard SLPS is built with desktop applications in mind: all licenses for the permutation/product/version combination are available to the user. However, in the Saas SDK we need to support the “Multi Tennant” problem of web applications.

From the licensing point of view this means that we need to add an additional dimension for licenses: per-tenant.

The Saas SDK captures this concept as a “License Partition”. This allows us to store licenses across multiple partitions. For example, in a multi-tenant application, all licenses that an individual tenant has installed will need to be stored in a single partition.

Obviously, it is not possible for the Saas SDK to implicitly understand your application and know how your users are associated with a particular tenancy. For example, some implementers may store tenant ID in an encrypted cookie; others may store it in the session; others may use MVC Route data.

Thus, the Saas SDK provides a simple interface that you must implement, which will return a unique string that identifies which partition (and therefore which licenses) the current request is using.

Obviously, it is not possible for the Saas SDK to implicitly understand your application and know how your users are associated with a particular tenancy. For example, some implementers may store tenant ID in an encrypted cookie; others may store it in the session; others may use MVC Route data.

Thus, the Saas SDK provides a simple interface that you must implement, which will return a unique string that identifies which partition (and therefore which licenses) the current request is using.

For example: 

using System;
using System.Web;
using Slps.Saas;

namespace TailSpin.Web.Utility
{
	public class TenantPartition : ILicensePartition
	{
		public string ComputeCurrentPartitionKey()
		{
				var tenantId = HttpContext.Current.Session["TenantId"] as string;
				if( !string.IsNullOrEmpty( tenantId ) )
					return tenantId;

				throw new ApplicationException( "Attempting to access license for empty tenant" );
		}
	}
}

Configure your Azure Storage Account

Out of the box, the Saas SDK requires that Slps Licenses are stored in an Azure Storage Account. You will need to create a Storage Account for storing the licenses.

Within this storage account, the Saas SDK will create an Azure Table called “SlpsLicenses” and a Blob store called “slps-licenses”. Even though these names are unlikely to clash with existing Azure table or blob containers used by your application in an existing storage account, we recommend that you create a dedicated storage account for storing your licenses: apart from this being good hygiene advice (keeping license data that you have no control over separate from your applications data), in the future we may support locking of licenses to a storage account and then this would become mandatory.

Make sure that you add the necessary configuration call that configures Cloud storage:

CloudStorageAccount.SetConfigurationSettingPublisher( 
(configName, configSetter) =>
	 configSetter( RoleEnvironment.GetConfigurationSettingValue( configName )));

If you are using a version of the Azure SDK prior to 1.4 (or you are using the legacy “Hosted Core” mode), then you only need to add that line to the RoleEntryPoint.OnStart() method.

If you are using Azure SDK 1.4 or greater (“IIS hosted” mode), the above statement will need to be added to both your RoleEntryPoint OnStart() method and also to your Application_Start() method of your Global.asax.cs.

Lastly, you will need to add the Storage Connection String to your Cloud .csdef and .cscfg files. So add the following to the ConfigurationSettings section of your .csdef file:

<Setting name="Slps.Saas.LicenseStore.Azure.DataConnectionString" />

Add the following to the ConfigurationSettings section of your .cscfg files (making sure to insert the correct values for your account):

<Setting name="Slps.Saas.LicenseStore.Azure.DataConnectionString"
value="DefaultEndpointsProtocol=https;AccountName=accountNameThatWillStoreLicenses;AccountKey=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX==" />

Bringing it all together

The final piece of configuration is to bring all the previous steps together and register the configuration at application start up.

You should thus add the following code to your Application_Start() method (in the Global.asax.cs) of your web application:

protected void Application_Start()
{
	…
	var slpsConfiguration = SlpsConfiguration.ComposeContextBuilder(
		x =>
		x.WithProductVersion("TailSpin", "1.0")
		.WithPermutationShortCode( "bcfd5" )
		.WithPartitioning<TenantPartition>()
		.CreateBuilder() );
	SlpsContext.Configure( slpsConfiguration );
}

There will be other configuration commands in your Application_Start() so these are in addition to any other configuration that you may have.
With the above Slps Saas configuration you would at least need configuration for your Azure Storage account.

Adding License Checks to your Web Application

There are two ways that you can use the Saas SDK to make license checks within your code: declaratively using attributes, or programmatically using the public API.

Load Licenses into the Current Principal

Regardless of which model you adopt, your application must first load licenses into the Identity of the current principal.  Once loaded, the SDK can make assertions against the valid licenses.

Because licence loading and evaluation is inherently a slow process, your application must explicitly tell the Saas SDK when to load licenses from the license store:  We feel you are best placed to judge the performance requirements of your application and when your application is going to need access to licenses.

Thus, out of the box, the Saas SDK uses a “Fail Fast License Provisioning Policy” which forces you to explicitly load the licenses from Azure Storage before you can perform tests upon them.

We also ship a “Lazy Load License Provisioning Policy” that will load the licenses when they are accessed but you must opt-in to get that behaviour.  To do that, you need to change your Slps configuration initialization by adding a call to the .WithLazyClaimsProvisioning() method:

	var slpsConfiguration = SlpsConfiguration.ComposeContextBuilder(
	    x => x.WithProductVersion( "TailSpin", "1.0" )
		.WithPermutationShortCode( "bcfd5" )
		.WithPartitioning<TenantPartition>()
		.WithLazyClaimsProvisioning()
		.CreateBuilder() );
	SlpsContext.Configure( slpsConfiguration );

To load licenses within an MVC application, you need to apply the ProvideAuthorizationClaims attribute to a controller method:

[HttpGet]
[ProvideAuthorizationClaims]
public ActionResult Index()
{
…
}

Alternatively, you can programmatically load the claims with the following:

SlpsContext.Current.Internal.PrincipalLicensing.LoadAuthorizationClaimsIfNotPresent();

You may have noticed that we have mentioned that the Saas SDK uses Windows Identity Foundation (WIF) and the previous two code snippets have used the word “claims”. What we are doing within the SDK is converting the InishTech proprietary license format into WIF “Claims”. These claims live in a IClaimsIdentity which in turn exists in a IClaimsPrincipal.

Out of the box, you do NOT need to configure your application to use WIF. We require that you add a reference to Microsoft.IdentityModel, but we do not require that you configure Federated Identity within your application: the Saas SDK will create a claims principal and store it in your HttpContext Items collection.

If you do have WIF configured in your application, then we recommend that you change from the out of the box behaviour and configure the Saas SDK to use the WIF identity. This is achieved by adding a call to
.WithWifClaimsPrincipalProvider():

	var slpsConfiguration = SlpsConfiguration.ComposeContextBuilder(
		x => x.WithProductVersion( "TailSpin", "1.0" )
		.WithPermutationShortCode( "bcfd5" )
		.WithPartitioning<TenantPartition>()
		.WithDefaultClaimsProvisioning() /*Could use .WithLazyClaimsProvisioning() here */
		.WithWifClaimsPrincipalProvider()
		.CreateBuilder() );
		SlpsContext.Configure( slpsConfiguration );

 Adding License Authorization

Once licenses have been loaded, you can then make Feature assertions against them. Features are declared against your product in the SoftwarePotential portal and licenses are issued in the portal with limitations (time & usage) declared against the features.

Your code can make authorization decisions against the issued licenses.

To make an authorization decision for a license feature in an MVC application, you can use the LicenseAuthorize attribute. In the following example, a valid license with the CreateSurvey feature must have been loaded before the controller method will execute.

[HttpGet]
[ProvideAuthorizationClaims]
[LicenseAuthorize("CreateSurvey")]
public ActionResult New([Deserialize]Survey hiddenSurvey)
{
    …
}

Programmatically, a license could be evaluated using the following syntax:

[HttpGet]
[ProvideAuthorizationClaims]
public ActionResult New([Deserialize]Survey hiddenSurvey)
{
	if (!SlpsContext.Current.Authorization.Has( "CreateSurvey" ))
		return new HttpUnauthorizedResult();
}

 

Provide a Controller Method for Activating License Keys

Of course, if no licenses are present, then the above code will fail with “Not Authorized” results. This is because your application has no licenses installed.

In typical provisioning flow, your sales people will issue license keys from the SoftwarePotential portal to your tenants (more advanced provisioning are possible and desirable using the web service APIs, but to help you to understand the concepts, let’s assume that activation keys are issued directly to your tenants). Those keys need to be redeemed within your application so that the SDK will can activate the key and install the associated license in to your Azure Storage Account.

Thus, your final integration point is to implement a controller method that will accept activation keys for a tenant.

[HttpPost]
public ActionResult Activate( string activationKey )
{
	SlpsContext.Current.Activation.Activate( activationKey );

	return this.RedirectToAction( "Index" );
}

This controller could accept a POST from a form in your application, or perhaps it could be a REST endpoint for an automated provisioning process.

Issue Licenses Suitable for Saas Activation

You now need to issue licenses from the SoftwarePotential portal that are suitable for consumption within your Saas application.

Follow the normal procedure for issuing licenses, but bear in mind the following guidance:

The Locking option should be set to None

This is because MS reserve the right to migrate Azure VMs to different machines according to a proprietary load algorithm. Therefore licenses cannot be locked to machines or even to VMs (they reserve the right to spin up new VMs for you during upgrade).

We do not support locking of licenses to an Azure Storage account.

Once you have an activation key, it can be redeemed against the Activation controller method that we created earlier.

Adding Feature Usage Logging to your Web Application

You may also wish to log usage of specific features in your application e.g. for billing purposes. The SaaS SDK provides you with the ability to specify in a license the features for which usage data should be logged.

Feature Usage Data Storage

Feature usage data will be logged in the Azure data table storage for the selected features with usage logging enabled. The logged data is partitioned by the supplied partioning function (in the same way as license data using ITenantPartition) and will contain the following elements

  • Feature Name and 
  • Created Date.

Enabling Usage Logging

In order to enable usage logging the GatherUsage flag should be set at either the license or feature level (for each of the features for which usage is to be logged) in a license created in SLP Online.  This flag will cause the usage to be logged automatically every time a feature is authorised.

Alternatively you can programmatically enable usage logging as follows:
 

SlpsContext.Current.Internal.LoggingService.LogFeatureEventOccurredIfGatherUsage("FeatureName");

Known Issues with version 3.1.1920

  • Code protection is not supported.
  • Enforcement of usage limits (at license and feature level) is not currently supported.
  • License locking is not currently supported. This means that licenses that are installed into the SlpsLicenses blob store can be copied and used in other storage accounts.
  • Be aware that the SoftwarePotential portal exposes license options that are not applicable to this release of our Saas licensing SDK. Including:
    • Renewable licenses are not currently supported. (Implies Grace Period is not currently supported)
    • Start Date for a license feature is not currently supported.
    • Max Instances per client is not supported.
    • Concurrent Usage on a feature is not supported.