четверг, 6 декабря 2012 г.

Version 7.1 of the Manco .NET Licensing System released

Manco .NET Licensing System version 7.1 is available now. You can get 15-days trial version at the http://www.mancosoftware.com/licensing/download.htm

List of the most significant changes made in the new version:

  1. Created own simplified implementation of the ClientFormsAuthenticationMembershipProvider which don't use offline authentication (don't store authentication cookies and password hash locally). It allows using of the Activation Web Service on the ASP.NET hostings which have not user profile for system users (like ASPNET or Network Services).
  2. Added ability for immediate deactivation of the product on the client side when ValidateProduct method of the AWS is called. For example, the customer requests a money-back so the protected application should stop working as soon as possible.  Setting of the allowed activations to 0 now mean that customer’s license is inactive and application should be switched to the evaluation mode (or start throw exception depends on the settings).
  3. The Floating License Service (FLWS) have been redesigned to be WCF service.
  4. Added ability to use floating license offline during specified timeframe.
  5. FLWS is able to unlock licenses automatically using time-frame rule set. For example, if locked license is older than 5 days then it should be unlocked. This feature works in conjunction with ability to use floating license offline. 
  6. Added ability to use Data Service as storage for the licenses in the FLWS.
  7. Changed the way the floating license usage is registered on the server. FLWS don’t use IP address for these purposes anymore. The IP address of the user PC can be changed between obtaining and release the license. For example, user is travelling and floating license is configured to be used in the offline mode for some time. Now FLWS uses unique Floating License Session ID for it. 
  8. Added separate method to free FLWS license to the floating license helper.
  9. Added ability to configure AWS timeout for the FLWS.
  10. Added DeactivateLicense method to FLWS. It simplifies moving of the floating licenses to the new hardware.
  11. Because of the changes in the floating license processing the expiration state of the evaluation license is validated on server now. If license expired then GetLicenseString returns empty string.
  12. The default value of the license rule in the “Included Rule” grid can be edited using same control type as it is used to set its value in the sale record.
  13. Added stop list for the e-Mail communications. The e-Mails will not be sent to the customers are included to this list. 
  14. Added support for "ref" parameters when creating wrapper for code encryption.
  15. Added several minor enhancements in the UI of the License Manager and License Shop.
  16. Fixed few minor bugs.

суббота, 10 декабря 2011 г.

Custom protected storage

During a long time Manco .NET Licensing System supported 2 kinds of the protected storage: Windows Registry and Isolated Storage. No matter that it looks like enough for most .NET Framework scenarios there are environments and applications which require another approach. For example, Windows Azure Partial Trust role have not access to the Windows Registry or Isolated Storage.  To make it possible to use our protection library in those scenarios we introduced ability to create custom protected storage which will better suit the needs of your application.

In this article I’ll show how custom protected storage can be implemented using very simple scenario using temporary files.

Note: Pay attentions, this is just an example which demonstrates how the custom protected storage can be implemented. The temp folder isn't a good and secure place to store licensing information.

Mostly implementation of the license protection is the same as for other licensing schemas. The difference is in the protected storage only. We suppose that you have read at least “Quick Start” section in our product documentation, so we will show the peculiarity of the custom protected storage only.
First of all you should change mode of the protected storage in the License Manager to the “Custom”:



Now you should regenerate ILicenseKeyProvider and replace it in the protected application.

As next step you should create class which will implement Manco.Licensing.IProtectedStorage interface:
[C#]
 
/// <summary>
/// Custom protected storage which uses temporary file.
/// Pay attentions, this is just an example which demonstrates how the
/// custom protected storage can be implemented. The temp folder isn't a good
/// and secure place to store licensing information.
/// </summary>
public class TempFileProtectedStorage : IProtectedStorage
{
       public TempFileProtectedStorage()
       {
       }
           
       /// <summary>
       /// Gets or sets path of the temporary file.
       /// </summary>
       private string FilePath
       {
             get;
             set;
       } 

       /// <summary>
       /// Gets or sets protected assembly.
       /// </summary>
       private Assembly ProtectedAssembly
       {
             get;
             set;
       } 

       /// <summary>
       /// Dispose protected storage object
       /// </summary>
       public void Dispose()
       {
       } 

       /// <summary>
       /// Gets stream to read license document from the protected storage
       /// </summary>
       /// <returns>Stream to read document from</returns>
       public System.IO.Stream GetInputStream()
       {
             FileStream fileStream = File.Open(this.FilePath,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.None);
             if (fileStream.Length > 0)
             {
                    StreamReader reader = new StreamReader(fileStream);
                    reader.ReadLine(); 

                    string lsEncrLicense = reader.ReadLine();
                    reader.Close();
                    fileStream.Close(); 

                    byte[] encrypted = Convert.FromBase64String(lsEncrLicense);
                    MemoryStream stream = new MemoryStream(encrypted); 

                    return stream;
             }
             else
             {
                    fileStream.Close();
                    return null;
             }
       } 

       /// <summary>
       /// Initialize protected storage.
       /// </summary>
       /// <param name="licenseKeyProvider">License key provider.</param>
       public void Initialize(ILicenseKeyProvider licenseKeyProvider)
       {
             this.FilePath = null; 

             // In this example we use name of the product to create
             // temporary folder.
             this.ProtectedAssembly = licenseKeyProvider.GetType().Assembly;
             AssemblyProductAttribute attribute =
                    (AssemblyProductAttribute)Attribute.GetCustomAttribute(
                    this.ProtectedAssembly, typeof(AssemblyProductAttribute));
             if (attribute != null && !string.IsNullOrEmpty(attribute.Product))
             {
                    string folderPath = Path.Combine(
Path.GetTempPath(), attribute.Product); 

                    if (!Directory.Exists(folderPath))
                    {
                           Directory.CreateDirectory(folderPath);
                    }                          

                    // Use public key as index to search license file.
                    string publicKey =
this.GetPublicKeyHexString(
this.ProtectedAssembly.GetName().GetPublicKey()); 

                    string[] files = Directory.GetFiles(folderPath);
                    foreach (string file in files)
                    {
                           try
                           {
                                  StreamReader loReader = new StreamReader(
File.Open(file,
FileMode.Open,
FileAccess.ReadWrite,
FileShare.None));
                                  string textLine = loReader.ReadLine();
                                  loReader.Close(); 

                                  if (textLine == publicKey)
                                  {
                                        this.FilePath = file;
                                        break;
                                  }
                           }
                           catch
                           {
                           }
                    }

                    if (this.FilePath == null)
                    {
                           this.FilePath = Path.Combine(
folderPath,
Path.GetRandomFileName());
                    }
             }
             else
             {
                    throw new ArgumentException("Product name isn't set in the protected assembly!");
             }
       } 

       /// <summary>
       /// Write byte array to the protected storage.
       /// </summary>
       /// <param name="toWrite">Byte array to write.</param>
       public void WriteByteArray(byte[] toWrite)
       {
             if (!string.IsNullOrEmpty(this.FilePath))
             {
                    FileStream fileStream = File.Open(
this.FilePath,
FileMode.Create,
FileAccess.Write,
FileShare.None);
                    StreamWriter writer = new StreamWriter(fileStream);
                    string publicKey = this.GetPublicKeyHexString(
this.ProtectedAssembly.GetName().GetPublicKey());
                    writer.WriteLine(publicKey); 

                    string lsEncrLicense = Convert.ToBase64String(toWrite);
                    writer.WriteLine(lsEncrLicense); 

                    writer.Close();
                    fileStream.Close();
             }
       } 

       private string GetPublicKeyHexString(byte[] publicKey)
       {
             string stringKey = string.Empty; 

             foreach (byte b in publicKey)
             {
                    stringKey += b.ToString("X2");
             } 

             return stringKey;
       }
}

[VB.NET]

''' <summary>
''' Custom protected storage which uses temporary file.
''' Pay attentions, this is just an example which demonstrates how the
''' custom protected storage can be implemented. The temp folder isn't a good
''' and secure place to store licensing information.
''' </summary>
Public Class TempFileProtectedStorage
       Implements IProtectedStorage 

       Public Sub New()
       End Sub 

       ''' <summary>
       ''' Gets or sets path of the temporary file.
       ''' </summary>
       Private Property FilePath() As String
             Get
                    Return m_FilePath
             End Get
             Set(value As String)
                    m_FilePath = value
             End Set
       End Property
       Private m_FilePath As String 

       ''' <summary>
       ''' Gets or sets protected assembly.
       ''' </summary>
       Private Property ProtectedAssembly() As Assembly
             Get
                    Return m_ProtectedAssembly
             End Get
             Set(value As Assembly)
                    m_ProtectedAssembly = value
             End Set
       End Property
       Private m_ProtectedAssembly As Assembly 

       ''' <summary>
       ''' Dispose protected storage object
       ''' </summary>
       Public Sub Dispose() _
        Implements IProtectedStorage.Dispose
       End Sub 

       ''' <summary>
       ''' Gets stream to read license document from the protected storage
       ''' </summary>
       ''' <returns>Stream to read document from</returns>
       Public Function GetInputStream() As System.IO.Stream _
         Implements IProtectedStorage.GetInputStream
             Dim fileStream As FileStream = File.Open( _
              Me.FilePath, _
              FileMode.OpenOrCreate, _
              FileAccess.ReadWrite, _
              FileShare.None)
             If fileStream.Length > 0 Then
                    Dim reader As New StreamReader(fileStream)
                    reader.ReadLine() 
                    Dim lsEncrLicense As String = reader.ReadLine()
                    reader.Close()
                    fileStream.Close()
                    Dim encrypted As Byte() = Convert.FromBase64String(lsEncrLicense)
                    Dim stream As New MemoryStream(encrypted)
                    Return stream
             Else
                    fileStream.Close()
                    Return Nothing
             End If
       End Function 

       ''' <summary>
       ''' Initialize protected storage.
       ''' </summary>
       ''' <param name="licenseKeyProvider">License key provider.</param>
       Public Sub Initialize(licenseKeyProvider As ILicenseKeyProvider) _
        Implements IProtectedStorage.Initialize
             Me.FilePath = Nothing 

             ' In this example we use name of the product to create
             ' temporary folder.
             Me.ProtectedAssembly = licenseKeyProvider.[GetType]().Assembly
             Dim productAttribute As AssemblyProductAttribute = _
              DirectCast(Attribute.GetCustomAttribute(Me.ProtectedAssembly, _
                              GetType(AssemblyProductAttribute)), AssemblyProductAttribute)
             If productAttribute IsNot Nothing _
              AndAlso Not String.IsNullOrEmpty(productAttribute.Product) Then
                    Dim folderPath As String = System.IO.Path.Combine( _
                     System.IO.Path.GetTempPath(), productAttribute.Product) 

                    If Not Directory.Exists(folderPath) Then
                           Directory.CreateDirectory(folderPath)
                    End If 

                    ' Use public key as index to search license file.
                    Dim publicKey As String = Me.GetPublicKeyHexString( _
                     Me.ProtectedAssembly.GetName().GetPublicKey()) 

                    Dim files As String() = Directory.GetFiles(folderPath)
                    For Each fileName As String In files
                           Try
                                  Dim loReader As New StreamReader( _
                                   File.Open(fileName, _
                                         FileMode.Open, _
                                         FileAccess.ReadWrite, _
                                         FileShare.None))
                                  Dim textLine As String = loReader.ReadLine()
                                  loReader.Close() 

                                  If textLine = publicKey Then
                                        Me.FilePath = fileName
                                        Exit Try
                                  End If
                           Catch
                           End Try
                    Next 

                    If Me.FilePath Is Nothing Then
                           Me.FilePath = System.IO.Path.Combine( _
                            folderPath, System.IO.Path.GetRandomFileName())
                    End If
             Else
                    Throw New ArgumentException("Product name isn't set in the protected assembly!")
             End If
       End Sub

       ''' <summary>
       ''' Write byte array to the protected storage.
       ''' </summary>
       ''' <param name="toWrite">Byte array to write.</param>
       Public Sub WriteByteArray(toWrite As Byte()) _
        Implements IProtectedStorage.WriteByteArray
             If Not String.IsNullOrEmpty(Me.FilePath) Then
                    Dim fileStream As FileStream = File.Open( _
                     Me.FilePath, _
                     FileMode.Create, _
                     FileAccess.Write, _
                     FileShare.None)
                    Dim writer As New StreamWriter(fileStream)
                    Dim publicKey As String = Me.GetPublicKeyHexString( _
                     Me.ProtectedAssembly.GetName().GetPublicKey())
                    writer.WriteLine(publicKey) 

                    Dim lsEncrLicense As String = Convert.ToBase64String(toWrite)
                    writer.WriteLine(lsEncrLicense) 

                    writer.Close()
                    fileStream.Close()
             End If
       End Sub 

       Private Function GetPublicKeyHexString(publicKey As Byte()) As String
             Dim stringKey As String = String.Empty 

             For Each b As Byte In publicKey
                    stringKey += b.ToString("X2")
             Next 

             Return stringKey
       End Function
End Class

The final step you have to do is informing the protection library about class which implements custom protected storage:

[C#]
// Instantiate license object and assign assemblies for validation.
this.license = (Manco.Licensing.License)LicenseManager.Validate(
             typeof(MainWindow), this); 

// Set type which implements custom protected storage.
// It must be done before any other operations with license object.
this.license.CustomProtectedStorageType = typeof(TempFileProtectedStorage); 

this.license.LicensedAssembly = typeof(MainWindow).Assembly;
this.licenseProperties = this.license.GetLicenseProperties();
this.licenseState = this.license.GetLicenseState(true); 

[VB.NET]
' Instantiate license object and assign assemblies for validation.
Me.license = LicenseManager.Validate(GetType(MainWindow), Me)

' Set type which implements custom protected storage.
' It must be done before any other operations with license object.
Me.license.CustomProtectedStorageType = GetType(TempFileProtectedStorage)
Me.license.LicensedAssembly = GetType(MainWindow).Assembly
Me.licenseProperties = Me.license.GetLicenseProperties()
Me.licenseState = Me.license.GetLicenseState(True)

You can find sample solution which demonstrates creation of the custom protected storage at the http://www.mancosoftware.com/licensing/download.htm.