Check if user belongs to K2 role

In your SharePoint (or other) / K2 solution, you may find yourself in a situation where you want to check if the current user belongs to a given K2 role. Perhaps, you want to allow only users who belong to particular K2 role to view a page, or you want to show a different page depending on the K2 role the user belongs to.


Surprisingly, K2 API does not provide a convenience method to do that. You have to implement it yourself. Even further, K2 Roles may contain ActiveDirectory groups and you will have to check if the current user belongs to them! In this article, we will discuss how all this is being done.

In the project where you will be implementing this method, make sure you have references to those libraries (which should be in the GAC):

  • SourceCode.HostClientAPI
  • SourceCode.Security.UserRoleManager.Management

First, let’s think about the signature of our method. It needs to return a boolean and receive a K2 role name as parameter:
public static bool CurrentUserBelongsToK2Role(string roleName)

That should do it. Now let’s start implementing the method. We need to get the name of the current user.
string loginName = WindowsIdentity.GetCurrent().Name;

(By the way, WindowsIdentity is in System.Security.Principal)

What we have so far is:
public static bool CurrentUserBelongsToK2Role(string roleName)
{
string loginName = WindowsIdentity.GetCurrent().Name;

// TODO: Implement further

return false;
}

Not much. We need to get an instance of K2’s UserRoleManager class. We will create a separate method which returns us an instance of this object:
public static UserRoleManager GetUserRoleManager()
{
UserRoleManager userRoleManager = new UserRoleManager();
userRoleManager.CreateConnection();
userRoleManager.Connection.Open(GetSCConnectionStringBuilder().ToString());

return userRoleManager;
}

And implement a second method, to get us a GetSCConnectionStringBuilder object.
public static SCConnectionStringBuilder GetSCConnectionStringBuilder()
{
SCConnectionStringBuilder connectionString = new SCConnectionStringBuilder();
connectionString.Authenticate = true;
connectionString.Host = ConfigurationSettings.AppSettings[“K2Server“];
connectionString.Integrated = true;
connectionString.IsPrimaryLogin = true;
connectionString.Port = uint.Parse(ConfigurationSettings.AppSettings[“K2ServerPort“]);

return connectionString;
}

Basically, this method will read K2Server and K2ServerPort keys from your config and use them for connection to K2. You are free to implement it any way you like. Now, when we have those two helper methods, we can finally do:
UserRoleManager userRoleManager = GetUserRoleManager();

Using the Role Manager, we will try to get an object representation of the K2 role we are checking against:
Role role = userRoleManager.GetRole(roleName);
if (role == null)
{
throw new Exception(“Role ” + roleName + ” not found!”);
}

So this piece of code will throw an exception in case the role we are trying to check does not exist. If it exists, our Role object will not be null. Now we need to enumerate the RoleItems within the role. Basically, it will give us all the users (or AD groups) included in this K2 role:
foreach (RoleItem roleItem in role.Include)
{
string currentRoleName = roleItem.Name;
}

Again, let’s see what we have so far:
public static bool CurrentUserBelongsToK2Role(string roleName)
{
string loginName = WindowsIdentity.GetCurrent().Name;

UserRoleManager userRoleManager = GetUserRoleManager();

Role role = userRoleManager.GetRole(roleName);
if (role == null)
{
throw new Exception(“Role ” + roleName + ” not found!”);
}

foreach (RoleItem roleItem in role.Include)
{
string currentRoleName = roleItem.Name;

// TODO: Implement here
}

return false;
}

So far so good, at least we are now able to enumerate all items within a K2 role! Let’s keep going and finish the implementation as marked in bold above.

The currentRoleName object could be returned to us in the format of K2:DOMAIN\Name. We need to normalize it to DOMAIN\Name (i.e. remove the ‘K2:’ part).
if (currentRoleName.IndexOf(‘:’) > -1)
{
currentRoleName = roleItem.Name.Split(‘:’)[1];
}

Now… the roleItem object we have (in the foreach statement) is of base type RoleItem. There are two classes which inherit from it – UserItem and GroupItem. This means, the current roleItem could be any of the two, which will help us understand if we are dealing with a single user or an ActiveDirectory group added to the K2 role. Let’s detect this:
if (roleItem is UserItem)
{
// TODO: Implement
}
else if (roleItem is GroupItem)
{
// TODO: Implement
}

Now we know when we are dealing with user and when with AD group. We just need to implement both cases. Implementing the UserItem case is as easy as comparing the currentRoleName to the loginName:
if (currentRoleName.ToLower() == loginName.ToLower())
{
// Found a USER match
userRoleManager.Connection.Close();
return true;
}

Implementing the GroupItem case is a little bit trickier. First, we need to implement a method which will return us a string array of the AD groups the current user belongs to, so we can later compare against them. Here is the code you will need:
private static string[] GetCurrentUserADGroups()
{
List groups = new List();

// Get the Groups of the current user
foreach (IdentityReference group in WindowsIdentity.GetCurrent().Groups)
{
// Ad the group to the list
NTAccount ntAcctGroup = group.Translate(typeof(NTAccount)) as NTAccount;
groups.Add(ntAcctGroup.Value.ToLower());
}

return groups.ToArray();
}

With the help of this method, we can get back to the implementation of the GroupItem case now:
else if (roleItem is GroupItem)
{
string[] loginNameADGroups = GetCurrentUserADGroups();
}

Then, we simply check if the loginNameADGroups contain the currentRoleName string (which in this case is an AD group).
if (loginNameADGroups.Contains(currentRoleName.ToLower()))
{
userRoleManager.Connection.Close();
return true;
}

And at the end of our CurrentUserBelongsToK2Role method we just have to add:
// No match found
userRoleManager.Connection.Close();
return false;

And that’s all! So, let’s see now how the whole thing looks:
public static bool CurrentUserBelongsToK2Role(string roleName)
{
string loginName = WindowsIdentity.GetCurrent().Name;

UserRoleManager userRoleManager = GetUserRoleManager();

Role role = userRoleManager.GetRole(roleName);
if (role == null)
{
throw new Exception(“Role ” + roleName + ” not found!”);
}

foreach (RoleItem roleItem in role.Include)
{
string currentRoleName = roleItem.Name;

// Is it K2:DOMAIN\Name ?
if (currentRoleName.IndexOf(‘:’) > -1)
{
// Get DOMAIN\Name
currentRoleName = roleItem.Name.Split(‘:’)[1];
}

if (roleItem is UserItem)
{
if (currentRoleName.ToLower() == loginName.ToLower())
{
// Found a USER match
userRoleManager.Connection.Close();
return true;
}
}
else if (roleItem is GroupItem)
{
string[] loginNameADGroups = GetCurrentUserADGroups();

if (loginNameADGroups.Contains(currentRoleName.ToLower()))
{
userRoleManager.Connection.Close();
return true;
}
}
}

// No match found
userRoleManager.Connection.Close();
return false;
}

Of course, you can find the whole project attached here.

Advertisements

How to create a K2 SmartObject

How does K2[blackpearl] integrate with other systems? One standard way to do this is through Web Services. And how does K2[blackpearl] integrate with Web Services? It is done through SmartObjects. So we have: K2 SmartObject Web Service Other System


“A K2 SmartObject can encapsulate data that does not currently reside in an existing system, such as data about an employee’s extracurricular activities, his or her family, or hobbies and interests. By using a SmartObject for employee information, all data about an employee is accessed in the same place, and updates are applied to the data at its source. It is important to remember that SmartObjects do not store or cache data. Once created, a SmartObject can be used and reused in a variety of ways; within K2 Designer for Visio, integrated for use in an InfoPath form, a workflow deployed via K2 Studio, in a report, in SharePoint, etc.”

SmartObject is all that and also it is the link between K2 and Web Services. So let’s see step by step how do we consume a Web Service method.

1. Create Web Service
First, let’s create a simple web service which we will be consuming later. For the purposes of the demonstration, it will be as simple as returning you the sum of two values.

I will use Visual Studio 2008 to create a new ‘ASP.NET Web Service Application’ project.

Let’s create the simple method ‘Sum’. See screenshot below:

Of course, you should test it first:

For the curious, it returned 3 😉

Ok, now we need to publish it somewhere in the network and make sure we can access it! Right click the solution, Publish.

‘Publish’ it somewhere on your local hard drive and make sure you map it in IIS to a virtual directory. You can do that by going into IIS, choose existing site (or create a new one), right click on it -> New Virtual Directory, browse to the path where you Published the service and keep clicking Next.

Let’s assume you published your service to http://localhost:86/SampleService/SampleService.asmx, which in the local network (if you have one) maps to http://192.168.0.1:86/SampleService/SampleService.asmx.

We are done with the service, it’s in the network, it works, it is ready to be registered as a service instance.

2. From K2 Workspace add it to Dynamic Web Service
Ok, now we have to add it to the ‘Dynamic Web Services’ list. Open your K2 Workspace. Go to Management -> Management Console -> Expand the servername -> SmartObjects -> Services -> Dynamic Web Service.

Click on the Add button and populate the URL field.

Click Next. In the next screen set names to something that makes sense to you and click Save. Let’s call it ‘Sample Service’.

You have now registered a service instance. Let’s verify that by going to the K2 server and opening C:\Program Files\K2 blackpearl\ServiceBroker (or C:\Program Files (x86)\K2 blackpearl\ServiceBroker) and run BrokerManagement.exe. On the first screen, click on ‘Configure Services’.
Under services -> DynamicWebService -> serviceinstances there should be an instance with a name ‘SampleService‘.

3. Create SmartObject
We are good to create a SmartObject around it now. Start a new instance of Visual Studio and create a new K2 SmartObject project.

The first thing you do is switch to Advanced mode.

Then Remove All methods that were created for you. We will start from scratch.

Then click on +Add and run the wizard that shows up in Advanced mode (it’s a checkbox on the first page).

Name the method Sum, make it Read type.

In the next screen, Configure Method Parameters, we will add the two parameters that we have to pass to the method – intA and intB. Make them ‘Number’s.

At the end, it should look like this:

Click Next. On the next screen you have to select the Service Method we will be executing. This is easy. First click Add, to start adding a service method call to the SmartObject. A new popup will show. There is a field ‘Service Object Method’ and next to it there is a ‘…’ button. Click on the button. It will open the Context browser. Browse through ServiceObjects Server -> Sample Service -> Sum -> Read.

Click Add in the Context Browser. You will see:

We need to map some fields now. See the ‘a’ and ‘b’ input properties? They are the web service method input parameters. We have to ‘bind’ them to the intA and intB fields we created for the SmartObject.

Click on the first one (‘a’), click ‘Assign’ button and a small pop up will appear. Set ‘Map to’ to ‘SmartObject Method Parameter’ and from the second dropdown select ‘intA’.

Then click ok and do the same thing for ‘b’, but select ‘intB’ instead. For ‘ReturnValue’ – click on it, Assign, set ‘Map To’ to SmartObject Property (i.e. you are storing the result in a property of the SmartObject). Then click Create.

You should end up with:

Click OK and finish the wizard.

Make sure you name your SmartObject properly.

4. Deploy
Right click the solution and do Rebuild. It should compile with no errors. Let’s deploy the SmartObject to our K2 Server. Right click the project -> Deploy. Follow the wizard (Next, Finish) and your SmartObject should be deployed.

5. Test
Let’s test your SmartObject. Log into the K2 server and go back to C:\Program Files (x86)\K2 blackpearl\ServiceBroker. Run the file SmartObject Service Tester.exe.

Expand the SmartObjects section, find your SampleServiceSmartObject, expand it until you see the Sum method.

Right click on it, Execute method. Populate the input fields and click ‘Sum’ button. Promptly, you should see the result displayed.

We just invoked the SmartObject, which talked to the WebService, retrieved result for us and was visualized in the test utility. Everything works perfectly, your SmartObject is ready to be consumed from a workflow!

6. Consume in Workflow
Create a new K2 Process Project in Visual Studio. I will reuse the K2 solution we already have and just add the new project to it.

From the Toolbox, drag and drop a new SmartObject event. On the second page, Wizard will prompt you for SmartObject Method. Browse to our Sum method in the SampleServiceSmartObject.

Click Add. It should look like this:

On the next screen, you have to provide values for the SmartObject input properties. This could be K2 DataFields from your process, or actual hardcoded sample values. For the purpose of the demo, we will just bind them to ‘2’ and ’54’. Select the property, click Assign button, set value, click ok. It should look like this:

On the next screen, we have to bind the return result to something. Let’s bind it to a DataField in the process which we will create. Click on the ReturnValue, click ‘Assign’, in the popup click on the ‘…’ button which will open the Context Browser. In this browser, either select already existing DataField, or create a new one on the fly (right click -> create). Make sure the field is Integer (for this demo). Select it, click ‘Add’, then ‘Ok’ in the pop up.

It should look like:

Click finish. You just finished adding a SmartObject event to your workflow. After this event is executed, you will have the value of ‘a’ + ‘b’ in the SumValue data field. I.e. you are consuming the SmartObject (and hence the Web Service).

Now you just need to finish the rest of the workflow 😉

7. Change the URL of the service
What if the address of your Web Service changes? Simple, go to the K2 server and open the C:\Program Files (x86)\K2 blackpearl\ServiceBroker folder. Run the BrokerManagement.exe app. On the first screen, click on ‘Configure Services’.

Find your service instance again:

Right click on it -> Configure Service. It will open a pop up. There you can change the URL field and click Save.

And that’s it, your service instance is now pointing to the right URL.

Basically that’s all. Now you know how to consume web services from your K2 Workflows, utilizing SmartObjects!

Hope this helps!

K2 [blackpoint] Installation Wrong Type of Database

By Hristo Yankov
As of today, you can install K2 [blackpoint] only on a clean (K2-free) environment. So if you are trying to install K2 [blackpoint] on an environment previously or currently used by K2 [blackpearl], you have no choice but uninstall K2 [blackpearl].

What you should be aware of, however, is the fact that the K2 [blackpearl] uninstaller does not remove the K2 databases (HostServer, Categories, Dependencies, etc) from the SQL server! If you try to install the K2 [blackpoint] databases on the same SQL server and haven’t deleted the K2 [blackpearl] databases manually, you will end up with the following errors during the K2 [blackpoint] installation:


So long story made short, make sure the K2 [blackpoint] database installation does not overlap with existing K2 [blackpearl] databases, as they are not being removed by uninstaller.

K2 Workspace 404 Not Found Error

By Hristo Yankov

In the process of a K2 installation, no matter distributed or on a single server, you have to setup the K2 Workspace. It is mostly well covered by the K2 Getting Started (Installation) documentation.

However, even if you follow strictly the instructions, you might get a 404 (Not Found) error when trying to access your Workspace. The following is a step by step guide on how to troubleshoot this error.


So you open your K2 Workspace and you are greeted by a 404 (Not Found) error. First thing you need to do is enable the logging of your K2 workspace web site. You can do that by running IIS Manager, navigating to Web sites, locating your K2 website, right clicking on it, selecting Properties from the context menu. It will open the properties of your web site. Navigate to the Web Site tab. There is a checkbox called ‘Enable Logging‘. Check it, and just in case do ‘iisreset’. Make a note of where the log is stored. It is usually in a C:\WINDOWS\system32\LogFiles\ folder.

Open your K2 Workspace site again, so the error is logged. Then navigate to the log folder and open the log file. You should see entries similar to:
YYYY-MM-DD HH:MM:SS W3SVCXXXX XX.XX.XX.XX GET /Workspace/default.aspx – 80 Domain\User XX.XX.XX.X long-client-description-entry-here 404 2 1260

The most important part of this error log is the error code. It is “404 2 1260”. 404, not found, could be caused by a couple of reasons. It is the “2” and “1260” part of this entry that specify what exactly it is. If you refer to this URL you will see that ‘2’ stands for “Web service extension lockdown policy prevents this request.” Basically, you have a policy, which is preventing the server from hosting the file.

Now, how to fix that? Go back to the IIS Manager and right click on the “Web Service Extensions” folder. From the context menu select “Allow all Web service extensions for specific application…”.

Then from the pop up window select ASP.NET v2.0 and click ok. iisreset and you should be fine.

If your error is not 404 x 2, but something else, the URL above should give you a hint on the root cause.

In the case of 404 x 2, this will fix your problem, but you might want to experiment with the Web Service Extensions policies, in order to achieve higher security level.

Troubleshooting Kerberos issues

By Hristo Yankov

Dealing with Kerberos in MOSS/K2 distributed environment is inevitable. First, let’s start with a quick overview of what is Kerberos.

From Wiki:

Kerberos is a computer network authentication protocol, which allows individuals communicating over a non-secure network to prove their identity to one another in a secure manner. It is also a suite of free software published by Massachusetts Institute of Technology (MIT) that implements this protocol. Its designers aimed primarily at a client-server model, and it provides mutual authentication — both the user and the server verify each other’s identity. Kerberos protocol messages are protected against eavesdropping and replay attacks.


What this means in the MOSS (with K2 worklist web part)/K2 context is:
End client’s browser requests MOSS page featuring the K2 web part, MOSS delegates the client’s credential to K2, K2 knows who the end user is and retrieves his or her worklist items.

Since this is a ‘troubleshooting Kerberos’ article and not ‘setting up Kerberos for first time’ we will assume that:

  • You have supposedly configured your network to work with it, by following the K2 documentation (Getting Started)
  • You went to the Active Directory on the Domain Controller and gave the computers and users participating in the process a Delegate right.
  • You have configured IIS to use Negotiate, rather than NTLM
  • You DO have worklist items waiting for you.
  • If you have more than one domain controller in the network you realize that replication time could be a problem. Make sure that if you do some domain changes (adding/removing SPN, trusting delegation and etc) you either force the replication or wait for the period of time. You might want to decrease it to 10-15 minutes.

Now, if you don’t see any of your items in the MOSS K2 web part, that’s the first sign your Kerberos setup is not working. Login to your K2 server (using the K2 Service credentials!), go to the Services and stop the BlackPearl service. Then run it in console mode so you can clearly see what the error is. Chances are, you will see error messages telling you that the user ‘NT AUTHORITY\ANONYMOUS LOGON’ was denied access.

Obviously what happens is – IIS is not passing the end client credentials to the next server in the chain, which in our particular case is the K2 server. Now starts the fun part, trying to determine why your Kerberos configuration is not working. Logically, you would start by enabling the Kerberos logging on all participating machines. You do that by running regedit and navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters. You should add a REG_DWORD entry with value of ‘1’. Also, on the machine issuing TGT you should add the key KerbDebugLevel with value of ‘1’, in the same Parameters folder. Enabling Kerberos logging is also explained here.

You might notice that Kerberos delays error logging, skips some or just doesn’t output when you expect it to. Eventually you will start seeing some logs in you Event Log viewer, System section. There might be gems such as:

  • KDC_ERR_S_PRINCIPAL_UNKNOWN
  • KDC_ERR_BADOPTION
  • KRB_ERR_RESPONSE_TOO_BIG
  • And other…

Microsoft tries to explain them here, but generally, the descriptions of those errors might be unclear or even misleading. During the course of a week-long Kerberos issue troubleshooting, the problem was pinpointed to the following items.

  1. Internet Explorer settings on the client side. Make sure that the client (using IE) has added your MOSS website to the list of Trusted Sites. This is done by going to the IE -> Tools -> Internet Options -> Security -> click on Trusted Sites -> Click on the Sites button -> type the url of the site and click Add. Also, make sure that the Security Level for the Trusted zone is Low. If that’s not possible, do a custom level (by pressing its button) and scroll down to the bottom of the pop up screen. Select “User Authentication->Logon->Automatic logon with current user name and password” radio button. Basically this tells the browser to pass the user credentials to the web site. Otherwise it will pass some anonymous user and it will never work.
  2. It is worth mentioning that IE 6 won’t work with Kerberos, if the web site is not running on port 80. It is explained in details here, but you can easily overcome this problem by using host headers, insted of ports.
  3. Kerberos UDP fragmentation. Yes, by default Kerberos is running over the unreliable UDP protocol. This means – there is no guarantee that the packages will actually reach the destination. So if you get a lot of KDC_ERR_S_PRINCIPAL_UNKNOWN and KRB_ERR_RESPONSE_TOO_BIG error logs, this might be the reason. It is explained here and the solution to that is right here. By setting the max packet size to 1, you force it to run over TCP. This will require reboot of the system, though.
  4. Duplicate SPNs. That is my favorite and less documented problem! To understand what is considered a duplicate, read this short article carefully! Turns out, you can not have “HTTP/portal.mydomain.com DOMAIN\ServiceA” AND “HTTP/portal.mydomain.com DOMAIN\ServiceB” in the same time! When you are adding a SPN, it should be assigned to only one user!

Getting rid of the duplicate SPNs is no fun at all. Currently, there is no good tool do that for you. You will have to do it manually. First, you will need to output all the current SPNs in your domain. It’s all explained here (3rd method).

  1. Get the spnquery.vbs script from here (click on the download button)
  2. Run it by executing “cscript spnquery.vbs * > my_SPNs.txt” in the command prompt
  3. Now you have all your SPNs dumped into the my_SPNs.txt file

Open it in your favorite text editor for review. Let’s assume your MOSS server is called “SRV-MOSS” and your domain is “domain.company”. Search the file for “SRV-MOSS”. You should see an entry like:

CN=SRV-MOSS,[…]
Class: computer
Computer DNS: […]
— HOST/SRV-MOSS.domain.company
— HOST/SRV-MOSS

It is fine. It shows that your MOSS server is trusted for delegation in the AD. Keep searching. You should see an entry similar to:

CN=[Application Pool Running User],[…]
Class: user
User Logon: [ApplicationPoolRunningUser]
— HTTP/SRV-MOSS
— HTTP/SRV-MOSS.domain.company

If the [ApplicationPoolRunningUser] is the domain user, running your MOSS web application pool, that is great, because it means that you have set a correct SPN! If you don’t find such entries at all, you have missed an important step and you need to add delegation, by running command similar to:

setspn -A HTTP/SRV-MOSS domain.company\ApplicationPoolRunningUser
setspn -A HTTP/SRV-MOSS.domain.company domain.company\ApplicationPoolRunningUser

However, if you find another user entry (different of your MOSS app. pool running user), listing HTTP/SRV-MOSS as service principal name, that’s a problem, because it’s a duplicate! You will need to remove it by executing:

setspn -D HTTP/SRV-MOSS domain.company\AnotherUser
setspn -D HTTP/SRV-MOSS.domain.company domain.company\AnotherUser

Search for other duplicates and if none, you are one step closer to resolving the problem. At this moment, it is great idea to Purge all current Kerberos tickets in the system, as they (and the lack of?!) are being cached for more than 20 hours. For that purpose, you need to obtain a copy of the free KerbTray program. You might already have it installed, so check in your Program Files\Resource Kits. If not, get it from here and disregard it’s saying the program is for Windows 2000 only. Here is a tip – if you are lazy and don’t want to install it on all machines, you can intall it on one and access it from the others by opening \\servername\C$\… (if enabled). The program usually runs fine that way, worst case you will have to copy it.

So, after you start KerbTray you will notice a new green icon in the system tray.

If you double click it will show you the current Kerberos tickets obtained for the system.

What you want to do is right click the icon and select ‘Purge Tickets’. Don’t worry, the system will obtain them again and that’s the whole point of the exercise.

Now go ahead and retest the network connectivity. Keep monitoring the K2 blackpearl server output. You should not see anonymous logons any more. Every network environment and its Kerberos configuration has something specific and its own flavor. Explore the references below to get further information and idea on how to troubleshoot Kerberos issues.

References:

InfoPath 2007 Digitally Signed Form Templates

By Hristo Yankov

If you are developing a K2 blackpearl / InfoPath 2007 / MOSS solution, at some point of time you might need to digitally sign your Form template. One of the reasons you may need to do that is, if you have to give ‘Full Trust’ to the form. That’s because MOSS will not allow you to submit (or event start filling out) a new InfoPath form, which requires full trust but is not digitally signed.

The process is pretty straight-forward – in InfoPath you click on the Tools in menu, select ‘Form Options’ and navigate to the ‘Security and Trust’ tab.

Then you click on the ‘Sign this form template’ checkbox and choose a certificate (or create a new one).


After doing this, you might be thinking that your InfoPath form is digitally signed and you can safely use the ‘Full Trust’ settings. In reality, after you deploy your solution and attempt to create a new InfoPath form in the Form Library, you get the following error:

“The form template is trying to access files and settings on your computer. InfoPath cannot grant access to these files and settings because the form template is not fully trusted. For a form to run with full trust, it must be installed or digitally signed with a certificate.”


Now, let’s think about how we usually edit InfoPath forms, which are already integrated with the K2 process. Usually we click on the InfoPath integration icon which opens the wizard and then we click on the ‘Design’ button, which opens the InfoPath application for us, so we can edit it.

(InfoPath Integration Wizard)

The problem with this approach is – by modifying the InfoPath form, K2 blackpearl invalidates your digital signature and effectively removes it. What happens is – you click on the ‘Design’ button, open the InfoPath form, set the signature, save the form, close it, ‘Finish’ the wizard, but next time you open the InfoPath form, your signature is gone. Even if you modify the InfoPath form outside the K2 studio, in the process of deployment, your signature is being destroyed again.

As a conclusion – there is no way you can deploy digitally signed InfoPath form, through the K2 blackpearl studio!

Fortunately there is a work-around. After deploying your solution, follow these steps:

  1. Navigate to your MOSS website
  2. Navigate to your Form Library where the form was deployed
  3. Click on Settings -> Form Library Settings
  4. Click on the ‘Advanced settings’ link
  5. Click on ‘Edit template’ link (Select ‘Yes’ at the question, if any)
  6. It will open the InfoPath form in design mode for you and will prompt you to save it somewhere. Don’t overwrite the InfoPath form which is in the K2 project. Just save this on the desktop, or somewhere else.
  7. Now, in the InfoPath go to the Tool -> Form Options… -> Security and Trust and select full trust radio-button.
  8. On the same screen – sign the form
  9. Save the InfoPath on the desktop again
  10. Use the Publishing wizard in the InfoPath application (File -> Publish…) to republish the form into the form library.

Now your InfoPath form is digitally signed and ready to use. Unfortunately, you will have to follow those steps after each deployment.