Impersonating the system user

Impersonating the system user

Old forum URL: forums.lhotka.net/forums/t/1319.aspx


MelGrubb posted on Monday, September 25, 2006

I've looked in several .NET books, including Rocky's, but I can't find a clear answer on this question.  What do you do when you need to "impersonate" the system user?  I maintain my own framework, so this isn't strictly a CSLA question, but I think it's something that's probably come up in CSLA's users as well, and I tend to find more technically savvy users and answers here than on the rest of the web/usenet/whatever.

For this example, just know that my framework "knows" who the current user is through the use of custom principal objects, and has a built-in set of security rules as to who is allowed to do what.  So far it's a lot like CSLA, although the details are very different under the board.  Unlike Rocky's design, I have no custom Identity object.  I take a WindowsIdentity or a GenericIdentity, and wrap my custom Principal object around it.  The principal object has all the brains and will figure out what rights the user has.  The annonymous ASP.NET account doesn't have a lot of rights, it can read some content on the site, but it's not allowed to really DO anything.  It is very very restricted.  

Now I want to add some self-signup to my site.  To do that the system is going to have to write some entries into tables that the anonymous account would not normally have access to.  I don't want to elevate the anonymous account's rights, and the Thread.CurrentPrincipal is going to be holding a reference to the anonymous account when the time comes to do the actual work.  What I'd like to do is have the code impersonate the service account that the site runs under when the user signs up.  Conceptually the anonymous user is not allowed to create other users, but the system could do it on their behalf.

I'd like the business object to be totally ignorant of this situation.  To them it should just look like they are being called on a thread owned by the system itself.  The security rules stay simple and straightforward, and there are no workarounds or back doors to worry about.  I don't want to slap some "god mode" semaphore on the principal.  I think that would be sloppy.  So what I really want is a best practices method of doing a kind of "run as".  I want to switch the execution over to the system account, run some code, and then revert back to the actual user when it's done.

Any opinions on the best way to accomplish this?

P.S. In case you're wondering why I hang out around the boards of a framework I don't actually use.  Like I said, I tend to find better opinions here than on the web as a whole.  The technical level of the discussions here eliminates a lot of the "noise" I find in the Usenet groups.

DeHaynes replied on Monday, September 25, 2006

If you are using SQL 2005 as your backend, you can pass the username as a parameter and execute the the code as that user.  The format is something like EXECUTE AS [user/role].  This link might help a little.

http://www.databasejournal.com/features/mssql/article.php/3596701

 

MelGrubb replied on Monday, September 25, 2006

In my case, it's not a matter of telling SQL Server who the user is.  All communications with SQL Server are through a specific service account.  It's more a matter of representing the user internally within the framework.

In my example, the anonymous user has next to no rights, but I'm providing a self-signup page where people can create their own accounts.  This is just the simplest example I could think of off the top of my head, and it could be solved easily enough by granting the anonymous user the rights to create new users, but that's not the point.  In my real world problem, the rules are a lot more complicated, but outside the scope of the question.

What I'm really trying to do is to temporarily change the principal that owns the current thread, perform some work on the user's behalf, and then switch the principal back to the way I found it when I'm finished.  It seems like the sort of thing that should come up fairly often, so I thought I'd see how the CSLA community has dealt with it.

RockfordLhotka replied on Monday, September 25, 2006

This doesn't sound like a framework issue. There are well-established patterns for handling impersonation within ASP.NET, and I would think one of them would work for you.

Most likely, given that you want to do the impersonation in one localized area of code, you'd want to use the method on WindowsIdentity (or Principal?) that let's you impersonate another user by using their credentials. That can be used in a block structure so you can do the impersonation for a small bit of code.

Alternately, what I've seen people do, is call a COM+ component, where that component is running in a Server Application, and thus can run under another account. Basically you treat that component like a service - calling it to do a specific task under that other identity.

MelGrubb replied on Monday, September 25, 2006

It's not a framework question per se'.  It's a question brought up BY the framework.  CSLA bases its security decisions based on information about the user which is stored in the custom principal (Or more accurately stored in the identity and EXPOSED by the principal).  So what do you do when you have to bend the rules?  To take my example, what do you do when you have to perform an operation that the current user is not allowed to do themself?

For another example, lets assume that deleting existing users is not a right we want to assign to the users group for obvious security reasons.  We DO, however, want to give users the right to cancel an account.  Logically the user does not possess the actual rights to delete themself, but in this one special case, and after a healthy round of "Are you really really sure?" messages, we want to allow the system itself to perform this action on the user's behalf.

Again, I'm not concerned about the arguably flawed design of the permissions in this simple example, it's just the simplest thing I can think of to illustrate the point.  Only Admins can delete users, but for a moment I want to pretend I'm an admin under very specific circumstances.

I've seen some examples of doing impersonation on a temporary basis.  I'm just wondering how you would work that into an application that is using CSLA for example?  Do you give the custom principal object an Impersonate method and let IT keep track of who it really is versus who it's pretending to be?  Do you let the outside method that needs to bend the rules change the current principal, in which case you have intimate knowledge about the inner workings of the security spread out all over the app?

I'm not so much looking for technical details of how to pull off impersonation, but rather best practices of how to accomplish it without getting lost in the process.  Or am I the only one who's ever tried this?

DeHaynes replied on Monday, September 25, 2006

   I haven't tested this, but I am thinking you could save the Principal from the current user. 

Csla.Security.BusinessPrincipalBase ExistingUserPrincipal = Csla.ApplicationContext.User;

Then log in as a user with higher access using your custom Principal

Csla.Security.ANBOPrincipal.Login("admin", "password", LDAP://DC=mydomain,DC=com);

I believe this would change your application context.  Then you could go ahead and do whatever you needed done under the higher privledges.  After you were done you could switch the Application Context back to the old user.

Csla.ApplicationContext.User = ExistingUserPrincipal;

 

Like I said, I am just doing this off the top of my head.  I haven't tested it but I hope it gives you some place to start.

 

 

DeHaynes replied on Monday, September 25, 2006

   FYI, the code listed here isn't exactly correct.  You won't find an ANBOPrincipal object under Csla.Security.  You will find Csla.Security.BusinessPrincipalBase which is where my custom principal inherits from. 

   Another thing you might find strange is the Login method. 

ANBOPrincipal.Login("admin", "password", LDAP://DC=mydomain,DC=com);

My custom principal uses a Criteria that has entries for the Username, password and domain.  It mixes Custom Authentication with Active Directory Authentication.  There is a post about it here:

http://forums.lhotka.net/forums/thread/6360.aspx

Copyright (c) Marimer LLC