K2 blackpearl Client Impersonation - Suggested Design Pattern
June 26th, 2008
The K2 blackpearl client API has impersonation functionality that I make heavy use of in my current project. A sample might look like this:
View CodeCSHARP | |
//Open a client connection (using a helper function) Connection conn = OpenK2ClientConnection(); //Impersonate the desired user conn.ImpersonateUser(userName); //Do whatever work you need to do as the impersonated user //Revert back to the original user conn.RevertUser(); | |
This works quite well, but you have to always be sure to call conn.RevertUser() at the end of your impersonation call so that you revert back to the original user (assuming you plan on reusing the same connection). If you don’t, you’ll continue to use the impersonated user context which will obviously lead to unintended consequences. To be safer, a try/finally makes for a better approach.
View CodeCSHARP | |
//Open a client connection (using a helper function) Connection conn = OpenK2ClientConnection(); try { //Impersonate the desired user conn.ImpersonateUser(userName); //Do whatever work you need to do as the impersonated user } finally { //Revert back to the original user conn.RevertUser(); } | |
The above code should always correctly revert our user, but it’s kind of a pain to write, results in a lot of “plumbing”/duplicate code and increases the chances implementing it will be overlooked somwhere. To overcome this, I recommend something like the following pattern be used:
View CodeCSHARP | |
Connection conn = OpenK2ClientConnection(); //Impersonate using( Impersonation.Impersonate(userName, conn ) { //Do whatever work you need to do as the impersonated user } | |
The result is a significant reduction in lines coded and guaranteed user revertion. This is accomplished by creating a custom class (Impersonation) which implements IDisposable and which always calls RevertUser at disposal. I use this approach in my BWT framework and it works flawlessly.
Here is my implementation of the Impersonation class:
View CodeCSHARP | |
public class Impersonation : IDisposable { private Connection _conn = null; private Impersonation(Connection conn) { _conn = conn; } #region Impersonate Methods public static Impersonation Impersonate(string userName, Connection conn) { conn.ImpersonateUser(userName); return new Impersonation(conn); } #endregion Impersonate Methods #region IDisposable Members public void Dispose() { _conn.RevertUser(); } #endregion } | |




