Custom SharePoint Designer Workflow Activity For Document Encryption!

Module #17: Custom Activities Lab #3

 

 

Course:           Advanced SharePoint Development

Estimated Time to Complete:  60 minutes

Objectives:

·        Create a custom workflow activity for SharePoint Designer

Operating Notes:  

·        None

Deliverables:

·        None

 

Overview:         Let’s create our own custom workflow using SharePoint Designer

Exercise 1 – Create a Custom Activity

Purpose:         Create a custom activity to be used by SharePoint Designer

Result:           
Custom Activity

Task 1 – Create a Project

  1. Open Visual Studio
  2. Select the File->New->Project
  3. Select Visual C#
  4. For template, select Workflow project type.
  5. Select the Workflow Activity Library template.
  6. For Location, type C:asp
  7. For Name, type CustomActivities
  8. Click OK
  9. Rename Activity1.cs to EncryptDocument.cs
  10. Right click the project, select Add Reference
  11. Add the following references:
    • C:program filescommon filesmicrosoft sharedweb server extenstionsisapiMicrosoft.SharePoint.dll
    • C:program filescommon filesmicrosoft sharedweb server extenstionsisapiMicrosoft.SharePoint.WorkflowActions.dll
    • C:Program FilesMicrosoft Enterprise Library 3.1 – May 2007BinMicrosoft.Practices.EnterpriseLibrary.Common.dll
    • C:Program FilesMicrosoft Enterprise Library 3.1 – May 2007BinMicrosoft.Practices.EnterpriseLibrary.Security.Cryptography.dll
  12. Right click the EncryptDocument shape, select View Code
  13. Add the following using statements for the Workflow code:
    • using Microsoft.SharePoint;
    • using Microsoft.SharePoint.Workflow;
    • using Microsoft.SharePoint.WorkflowActions;
  14. Since we are going to use Enterprise library to do our encryption, add the following using statements:
    • using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
    • using Microsoft.Practices.EnterpriseLibrary.Security;
    • using Microsoft.Practices.EnterpriseLibrary.Security.Cryptography;
  15. Add the following Execute method:


protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)

        {

            SPSite site = (SPSite)__Context.Site;

            SPWeb web = (SPWeb)__Context.Web;

            this.ListId.Trim();

            this.ListId.ToLower();

            Guid listGUID = new Guid(this.ListId);

            SPList list = web.Lists[listGUID];

            SPListItem item = list.GetItemById(this.ListItem);

 

            SPFile file = item.File;

            byte[] bytes = file.OpenBinary();

 

            //encrypt the file

            IConfigurationSource source = new SystemConfigurationSource();

            SymmetricCryptoProviderFactory factory = new SymmetricCryptoProviderFactory(source);

            ISymmetricCryptoProvider provider = factory.CreateDefault();

 

            byte[] encryptedByteArray = provider.Encrypt(bytes);           

            file.SaveBinary(encryptedByteArray);

            file.Update();

 

            return ActivityExecutionStatus.Closed;

        }       

 

  1. Add the following property, this will provide access to the workflow context back to our code:


public static DependencyProperty __ContextProperty = System.Workflow.ComponentModel.DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof(EncryptDocument));

 

        [Description("Workflow Context")]

        [Category("Context")]

        [ValidationOption(ValidationOption.Required)]

        [Browsable(true)]

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]

        public WorkflowContext __Context

        {

            get

            {

                return ((WorkflowContext)(base.GetValue(EncryptDocument.__ContextProperty)));

            }

            set

            {

                base.SetValue(EncryptDocument.__ContextProperty, value);

            }

        }

 

  1. Add the following ListId property:


public static DependencyProperty ListIdProperty = System.Workflow.ComponentModel.DependencyProperty.Register("ListId", typeof(string), typeof(EncryptDocument));

 

        [Description("This is the description which appears in the Property Browser")]

        [Category("This is the category which will be displayed in the Property Browser")]

        [ValidationOption(ValidationOption.Required)]

        [Browsable(true)]

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]

        public string ListId

        {

            get

            {

                return ((string)(base.GetValue(EncryptDocument.ListIdProperty)));

            }

            set

            {

                base.SetValue(EncryptDocument.ListIdProperty, value);

            }

        }

 

  1. Add the following ListItem property:


public static DependencyProperty ListItemProperty = System.Workflow.ComponentModel.DependencyProperty.Register("ListItem", typeof(int), typeof(EncryptDocument));

 

        [Description("This is the description which appears in the Property Browser")]

        [Category("This is the category which will be displayed in the Property Browser")]

        [ValidationOption(ValidationOption.Required)]

        [Browsable(true)]

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]

        public int ListItem

        {

            get

            {

                return ((int)(base.GetValue(EncryptDocument.ListItemProperty)));

            }

            set

            {

                base.SetValue(EncryptDocument.ListItemProperty, value);

            }

        }

 

 

  1. Add another Activity, name this one DecryptDocument
  2. Add the same using statements (steps 13,14) and the same properties (steps 16,17,18)
  3. Add the following Execute method:


protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)

        {

            SPSite site = (SPSite)__Context.Site;

            SPWeb web = (SPWeb)__Context.Web;

            this.ListId.Trim();

            this.ListId.ToLower();

            Guid listGUID = new Guid(this.ListId);

            SPList list = web.Lists[listGUID];

            SPListItem item = list.GetItemById(this.ListItem);

 

            SPFile file = item.File;

            byte[] bytes = file.OpenBinary();

 

            //encrypt the file

            IConfigurationSource source = new SystemConfigurationSource();

            SymmetricCryptoProviderFactory factory = new SymmetricCryptoProviderFactory(source);

            ISymmetricCryptoProvider provider = factory.CreateDefault();

 

            byte[] encryptedByteArray = provider.Decrypt(bytes);

            file.SaveBinary(encryptedByteArray);

            file.Update();

 

            return ActivityExecutionStatus.Closed;

        }

 

  1.  

 

Task 2 – Strong Name the assembly

  1. In the Solution Explorer, Right Click on Properties
  2. Click the Signing tab
  3. Check the checkbox, Sign the Assembly
  4. Select the New option from the Drop down below
  5. For Filename, type DocumentEncryption
  6. Uncheck the “Protect my key file with a password” option
  7. Compile the project

Task 3 – Copy to the GAC

  1. Copy the EncryptDocument.dll to the C:windowsassembly directory
  2. Copy the Enterprise Library dlls to the GAC as well
    • C:Program FilesMicrosoft Enterprise Library 3.1 – May 2007BinMicrosoft.Practices.EnterpriseLibrary.Common.dll
    • C:Program FilesMicrosoft Enterprise Library 3.1 – May 2007BinMicrosoft.Practices.EnterpriseLibrary.Security.Cryptography.dll

Task 4 – Modify the web.config file

  1. Open web.config file in the C:inetpubwwwrootwssvirtualdirectories100 directory
  2. Add the following element to the System.Workflow.ComponentModel.WorkflowCompiler element:


<authorizedType

   Assembly="CustomActivities,Version=1.0.0.0,Culture=neutral,PublicKeyToken=[YOUR PUBLICKEYTOKEN]"

    Namespace="CustomActivities"

    TypeName="*"

    Authorized="True" />

 

  1. Save and close the web.config file
  2. Open Enterprise Library Configuration tool (shortcut on the desktop)
  3. From EntLib, open the web.config file
  4. Right click the “C:inetpub…” node, select New->Cryptography Application Block
  5. Right Click the Symmetric Providers node, select New->Symmetric algorithm provider
  6. Select DESCryptoServiceProvider
  7. Click Ok
  8. In the Cryptographic Key Wizard dialog, Click Next
  9. Click Generate
  10. Click Next
  11. Save the key file to the c:inetpubwwwrootwssvirtualdirectories100 directory, call it EncryptIt
  12. Click Save
  13. Click Next
  14. Select Machine Mode
  15. Click Finish
  16. Click the Cryptography Application Block node
  17. For DefaultSymmetricCryptoProvider, select the DESCryptoServiceProvider
  18. Save the web.config file

Task 5 – Create an ACTIONS file

  1. Create a file in C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATE1033Workflow called ENCRYPT.ACTIONS
  2. Copy the following to the file:


<?xml version="1.0" encoding="utf-8"?>

<WorkflowInfo Language="en-us">

  <Actions>

<Action

    Name="Encrypt a document/item"

    ClassName="CustomActivities.EncryptDocument"

    Assembly="CustomActivities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=[PUBLICKEYTOKEN]"

    AppliesTo="all"

    Category="Encryption">

    <RuleDesigner Sentence="Encrypt %1 Item">

              <FieldBind Field="ListId,ListItem,ItemProperties" Text="this list" Id="1" DesignerType="UpdateListItem" />

         </RuleDesigner>

         <Parameters>

              <Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext" Direction="In" />

              <Parameter Name="ListId" Type="System.String, mscorlib" Direction="In" />

              <Parameter Name="ListItem" Type="System.Int32, mscorlib" Direction="In" />

              <Parameter Name="ItemProperties" Type="System.Collections.Hashtable, mscorlib" Direction="In" />

         </Parameters>

</Action>

<Action

    Name="Decrypt a document/item"

    ClassName="CustomActivities.DecryptDocument"

    Assembly="CustomActivities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=[PUBLICKEYTOKEN]"

    AppliesTo="all"

    Category="Encryption">

    <RuleDesigner Sentence="Decrypt %1 Item">

              <FieldBind Field="ListId,ListItem,ItemProperties" Text="this list" Id="1" DesignerType="UpdateListItem" />

         </RuleDesigner>

         <Parameters>

              <Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext" Direction="In" />

              <Parameter Name="ListId" Type="System.String, mscorlib" Direction="In" />

              <Parameter Name="ListItem" Type="System.Int32, mscorlib" Direction="In" />

              <Parameter Name="ItemProperties" Type="System.Collections.Hashtable, mscorlib" Direction="In" />

         </Parameters>

</Action>

  </Actions>

</WorkflowInfo>

 

Task 6 – Create a workflow to use the Encryption action

  1. Reset IIS
  2. Open SharePoint Designer 2007
  3. Open your site (http://loclhost:100)
  4. Select File->New->Workflow menu command.
  5. For Name, type “Encrypt It”, select Shared Documents from the dropdown
  6. Click Next
  7. Click Actions, select the More Actions
  8. Click the dropdown for the Select a Category and choose “Encryption”
  9. In the Choose an Action box, select the “Encrypt a document/item” activity
  10. Click Add.
  11. Click on “this” option in the Action
  12. From the Choose List Item dialog box, select the “Current Item” option
  13. Click OK
  14. Click Finish

Task 7 – Run the workflow

  1. Add an item to the document library
  2. Right click the JavaScript dropdown, select workflows
  3. Click Encrypt It

Task 8 – Try to open the document

  1. Click the document, Word should fail to open it…it is encrypted!!!

Task 9 – Create a workflow to use the Decryption action

  1. In SharePoint Designer 2007, select File->New->Workflow menu command.
  2. For Name, type “Decrypt It”, select Shared Documents from the dropdown
  3. Click Next
  4. Click Actions, select the More Actions
  5. Click the dropdown for the Select a Category and choose “Encryption”
  6. In the Choose an Action box, select the “Decrypt a document/item” activity
  7. Click Add.
  8. Click on “this” option in the Action
  9. From the Choose List Item dialog box, select the “Current Item” option
  10. Click OK
  11. Click Finish

Task 10 – Run the workflow

  1. Add an item to the document library
  2. Right click the JavaScript dropdown, select workflows
  3. Click Decrypt It

Task 11 – Try to open the document

  1. Click the document, Word will open…it is decrypted!!!

SharePoint 2007 Document Encryption

Since releasing the new Advanced SharePoint Development course, I have been working on various items to add to it!  One of them is using Enterprise Library with SharePoint Event Handlers to implment document encryption!  Here is the lab!

Module #15: SharePoint Event Handlers Lab #3

 

 

Course:           Advanced SharePoint Development

Estimated Time to Complete:  45 minutes

Objectives:

·        Create an Event Handler feature that encrypts documents

Operating Notes:  none

Deliverables:

·        None

 

Overview:         SharePoint has exposed several events that we can tie into with our own code.  Let’s see how to do this!

Exercise 1 – Create a new SharePoint Event Handler

Purpose:         Create and register an event handler for SharePoint events

Result:           
A new event handler

Task 1 – Create a new Visual Studio Class Library

  1. Open Visual Studio, select New->Project
  2. Select Class Library from the project templates
  3. Name the project EncryptDocumentEventReceiver
  4. For location, c:asp
  5. Add a reference to
    • Microsoft.SharePoint.dll
    • Microsoft.Practices.EnterpriseLibrary.Common
    • Microsoft.Practices.EnterpriseLibrary.Security
    • Microsoft.Practices.EnterpriseLibrary.Security.Cryptography
  6. Add a using statement to
    • Micorosft.SharePoint
    • Microsoft.Practices.EnterpriseLibrary.Common;
    • Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
    • Microsoft.Practices.EnterpriseLibrary.Security;
    • Microsoft.Practices.EnterpriseLibrary.Security.Configuration;
    • Microsoft.Practices.EnterpriseLibrary.Security.Cryptography;
  7. Rename class1 to EncryptDocument
  8. Make EncryptDocument inherit from SPItemEventReceiver
  9. Add the following methods:

private void Encrypt(SPItemEventProperties properties)

        {

            //get the file, encrypt it

            SPFile file = properties.ListItem.File;

            byte[] bytes = file.OpenBinary();

 

            //encrypt the file

            IConfigurationSource source = new SystemConfigurationSource();

            SymmetricCryptoProviderFactory factory = new SymmetricCryptoProviderFactory(source);

            ISymmetricCryptoProvider provider = factory.CreateDefault();

 

            byte[] encryptedByteArray = provider.Encrypt(bytes);

            string encryptedText = Convert.ToBase64String(encryptedByteArray);

 

            file.SaveBinary(encryptedByteArray);

            file.Update();    

        }

 

        private void Decrypt(SPItemEventProperties properties)

        {

            //get the file, encrypt it

            SPFile file = properties.ListItem.File;

            byte[] bytes = file.OpenBinary();

 

            //encrypt the file

            IConfigurationSource source = new SystemConfigurationSource();

            SymmetricCryptoProviderFactory factory = new SymmetricCryptoProviderFactory(source);

            ISymmetricCryptoProvider provider = factory.CreateDefault();

 

            byte[] decryptedByteArray = provider.Decrypt(bytes);

            string decryptedText = Convert.ToBase64String(decryptedByteArray);

 

            file.SaveBinary(decryptedByteArray);

            file.Update();           

        }

 

        public override void ItemCheckedOut(SPItemEventProperties properties)

        {

            Decrypt(properties);

 

            base.ItemCheckedOut(properties);

        }

 

        public override void ItemCheckedIn(SPItemEventProperties properties)

        {

            Encrypt(properties);

 

            base.ItemCheckedIn(properties);

        }

       

        public override void ItemAdded(SPItemEventProperties properties)

        {

            Encrypt(properties);

 

            base.ItemAdded(properties);

        }       

 

  1. Right Click the project, select Properties
  2. Select the Signing tab
  3. Click “Sign the assembly”
  4. Select <New…>, type EncryptDocumentEventReceiver.snk
  5. Uncheck “Password…”
  6. Build the project, Press Ctrl-Shift-B
  7. Copy the C:ASPEncryptDocumentEventReceiverEncryptDocumentEventReceiverinDebugEncryptDocumentEventReceiver.dll to the c:windowsassembly directory (this installs the assembly in the gac)

Task 2 – Extend the web.config file

  1. Open Enterprise Library console
  2. Click the open button, browse to the c:inetpubwwwrootwssvirtualdirectories100web.config file
  3. Click Open
  4. Right click the “C:inetpub…” node, select New->Cryptography Application Block
  5. Right click the Symmetric Provider node, select New->Symmetric Algorithm Provider
  6. Select TripleDESCryptoServiceProvider, Click Ok
  7. In the Cryptographic key wizard, Click Next
  8. Click Generate
  9. Click Next
  10. Name the key “EncryptIt.key”, Click Save
  11. Click Next
  12. Select Machine mode, Click Finish
  13. Click the Cryptography Application Block node
  14. For DefaultSymmetricCryptoProvider, select TripleDESCryptoServiceProvider

Task 3 – Create a console application to register the event handler

  1. In Visual Studio, click Add->New->Project
  2. Select a Windows Console Application
  3. Modify the Main method to this:


static void Main(string[] args)

        {

            try

            {

                SPSite site = new SPSite("http://localhost:100");

                SPWeb web = site.OpenWeb();

 

                SPEventReceiverDefinitionCollection receivers = web.EventReceivers;               

                SPEventReceiverDefinition newRecevier = receivers.Add();

                newRecevier.Name = "EncryptDocumentItemAdded";

                newRecevier.Assembly = "EncryptDocumentEventReceiver, Version=1.0.0.0, Culture=neutral,PublicKeyToken=3041621ef2536dab";

                newRecevier.Class = "EncryptDocumentEventReceiver.EncryptDocument";

                newRecevier.Type = SPEventReceiverType.ItemAdded;

                newRecevier.Update();

 

                newRecevier = receivers.Add();

                newRecevier.Name = "EncryptDocumentItemCheckedOut";

                newRecevier.Assembly = "EncryptDocumentEventReceiver, Version=1.0.0.0, Culture=neutral,PublicKeyToken=3041621ef2536dab";

                newRecevier.Class = "EncryptDocumentEventReceiver.EncryptDocument";

                newRecevier.Type = SPEventReceiverType.ItemCheckedOut;

                newRecevier.Update();

 

                newRecevier = receivers.Add();

                newRecevier.Name = "EncryptDocumentItemCheckedIn";

                newRecevier.Assembly = "EncryptDocumentEventReceiver, Version=1.0.0.0, Culture=neutral,PublicKeyToken=3041621ef2536dab";

                newRecevier.Class = "EncryptDocumentEventReceiver.EncryptDocument";

                newRecevier.Type = SPEventReceiverType.ItemCheckedIn;

                newRecevier.Update();               

            }

            catch (Exception ex)

            {

                Console.Write(ex.Message);

            }

        }

 

 

  1. Compile the project (Ctrl-Shift-B)
  2. Run the Console Project
  3. Reset IIS
  4. Open the http://localhost:100 site
  5. Create a text document, upload it to the document library
  6. Open the document, notice it is encrypted
  7. Check out the document
  8. Open the document, it is now decrypted!