Could somebody please help me understand the concept of 'impersonation'?
The way I understand it is that when impersonation occurs, code executes on behalf of some identity.
So, for a web page, as long as impersonation is disabled, the web page will always run under its configured account.
If it’s enabled, I can ‘override’ its default account and set the account under which I want the web application to run.
So if I'm using IIS7 and I have the following:
- An application pool with identity set to a Custom account ‘user1’.
- An asp.net web site, with its application pool set to the one above, and with impersonation disabled.
- Windows authentication enabled.
I also have the following code:
IIdentity ii= Thread.CurrentPrincipal.Identity;
IIdentity iii = Page.User.Identity;
If I access the page, I’m asked for windows credentials, I introduce ‘user2’ credentials.
As impersonation is disabled, I’d expect the IIdentity name to be ‘user1’, which it isn’t its ‘user2’.
Can somebody help me understand what’s going on? I guess I completely misunderstand the concept of ‘impersonation’.
Thanks
UPDATE 1
I came across this link after searching for a while:
http://msdn.microsoft.com/en-us/library/aa302377.aspx
It seems like there are three IIdentity objects.
HttpContext.Current.User.Identity
Thread.CurrentPrincipal.Identity
WindowsIdentity i2 = WindowsIdentity.GetCurrent();
From the link I understand that:
HttpContext.Current.User.Identity: Represents the current user requesting the page.
Thread.CurrentPrincipal.Identity: Identity currently executing the thread. I guess that this identity will be the one under which the current web request runs and its asp.net roles will define what the user can and can’t do in the application.
I suppose most of the times both HttpContext.Current.User.Identity and Thread.CurrentPrincipal.Identity would be the same user, but for some scenarios I guess the user requesting the page and the Thread.CurrentPrincipal.Identity could be different.
Then there’s:
WindowsIdentity i2 = WindowsIdentity.GetCurrent();
The link says: “WindowsIdentity = WindowsIdentity.GetCurrent(), which returns the identity of the security context of the currently executing Win32 thread.”
After doing a few tests enabling a disabling ‘impersonation’ and for my current scenario, I find that this is the Identity that gets impersonated.
If I don’t impersonate, ‘WindowsIdentity.GetCurrent();’ would reflect the configured user in the application pool and if I do impersonate, the identity changes to the one I’ve set in web.config:
<identity impersonate="true" password="**" userName="****" />
UPDATE 2
And if I set the web.config as:
<identity impersonate="true" />
WindowsIdentity.GetCurrent() gets impersonated as the user making the request so:
HttpContext.Current.User.Identity
Thread.CurrentPrincipal.Identity
WindowsIdentity.GetCurrent()
Are the same user, the user requesting the page.
When using impersonation, ASP.NET applications can optionally execute with the identity of the client on whose behalf they are operating. The usual reason for doing this is to avoid dealing with authentication and authorization issues in the ASP.NET application code. Instead, you rely on IIS to authenticate the user and either pass an authenticated token to the ASP.NET application or, if unable to authenticate the user, pass an unauthenticated token.
From Very good Article ASP.NET Impersonation
Related
We are going enhance the authentication and authorization system of our Intranet web app. After having few days reading about ADFS, STS, claim based authentication, asp.net Identity. Still not sure how these things works together.
Most of our intranet web applications are using Windows Integrated Authentication, we uses windows group or AzMan to do role base authorization. We have few applications(Vendor application) use it own user database and form base authentication.
We want to add following features to our web applications.
For Windows Authentication application, we want to let user to Sign Out / Sign in as different user. So when User A using his/her computer to access the application, it will auto logged in (default windows integrated authentication). When he/she do log out, it will redirect to a form to allow to input other user credential.
We want to allow user login to System A using System B username/password.
e.g. For the windows authentication application, we want allow user login to the application using the credential of the Form base application (Vendor application) of via visa
I don't know if ADFS can solve these two problems.
From my understanding, the main purpose of ADFS is to allow access to internal application from Internet, and it require SSL.
Our application all are in Intranet, and we don't want to manage the ssl cert.
But by using ADFS, perhaps I can enable both Windows and Form Authentication on my application, so then let use log out and re-direct him to the login form as which just like he access outside company network. It should solve the problem 1.
For problem 2, what if I can create a custom STS to issue security token by using the user database of the form base authentication appliaction. Then I can use claim based authentication and allow one application can use ADFS and my STS. It should solve my problem 2.
Is my direction correct? or am I complicated the problem?
ADFS will not work without SSL.
Furthermore, all RP have to use SSL.
Internally, users will be logged in seamlessly using WIA. When they logout, they will simply be seamlessly logged in again.
Also ADFS v3.0 and below can only authenticate against AD.
While what you want is possible using ADFS, the question is whether it's a good idea and worth the trouble. It may be more appropriate to ask the user to log out of the machine and log in with a different account so you can stick with Integrated Windows Authentication (IWA). Writing your own security infrastructure is fraught with peril.
If you really feel these are hard requirements and it is worth the trouble, the following may work.
Write an ASP.NET web application based on Katana and enable Integrated Windows Authentication. This will make sure that the first time a completely unauthenticated request comes in, the application will challenge the browser. Subsequent requests will have a WindowsPrincipal populated in the HttpContext.User and Thread.CurrentPrincipal.
Now, write a piece of OWIN middleware that checks if an authentication cookie is present. If the cookie is not present, it checks the Thread.CurrentPrincipal and serializes the claims into a secure cookie.
If the security cookie is present, it overwrites the WindowsPrincipal in Thread.CurrentPrincipal with a new ClaimsPrincipal created from the claims in the cookie.
Now, when a user navigates to the web application the first time, he/she will be logged in automatically using IWA and the cookie will be created. Now, provide a logout action which deletes the authentication cookie and presents the user with a username and password dialog.
In the POST handler for that action, use WIF to talk to the username endpoint in ADFS (using WS-Trust protocol) and try to authenticate the user with the supplied credentials. If successful, use the claims from the returned token to create a new authentication cookie.
I'm building web portal in ASP.NET MVC 3 that uses distant web service as only way to communicate with database. Web service has requirement to always have Username/Password passed in request header, otherwise it rejects the call.
I have overridden ASP.NET Membership so that my ValidateUser method sends Username/Password to web service Login method, and returns true/false if authentication is successful. It works quite nice with AcountController provided with MVC 3 Empty internet template. Since I have to pass Username/Password on every web service call, I'm saving them in Session.
My problem is:
If I close browser and reopen it... I remain logged to website, but my Session variables are expired, so none of my requests to web service are being accepted, even though I'm still logged with credentials.
I'm looking for nice suggestion how to sync user logged in state with session state. Either to keep them both persistent until log off is used or to have them both dispose on browser being closed.
Thanks for all suggestions :)
When the user signs in using your AccountController, try setting the auth cookie like this:
FormsAuthentication.SetAuthCookie(model.UserName, false);
This should tell ASP.NET to delete the cookie when the browser window is closed. Then, when user opens up a new browser, both the session and the auth cookie should both be destroyed.
Sessions are cookies on the client side. Forms Authentication (which uses your membership provider) also uses cookies.
They are different.
Is your auth ticket or cookie persistent? This MS KB will explain things and scenarios in more detail than I would here...
Hth.
I am currently working on an ASP .NET application which involves the user logging in using Windows Authentication. This causes both the HTTPContext.User and Thread.Principal to be set with the same credentials as the user logging in which is expected behaviour, while the WindowsIdentity stays as the IIS .NET AppPool user.
I have recently noticed in the application logs that there appears to be one request (normally the 5th-ish request on loading the page) where the WindowsIdentity starts off as the IIS user but ends up being elevated to the user who is logging in.
This only appears to be happening when the user is accessing the root path (for instance http://localhost/). If I specify any other exact path such as http://localhost/index.aspx this request does not appear to occur and the WindowsIdentity never changes.
Looking through the (rather large) codebase I can only find one method that impersonates a WindowsIdentity, but that method is not called apart from in specific circumstances on a specific page.
I was wondering why this might be happening and if there was any reason that IIS might be doing it by itself.
As per me i think the root(http://localhost) access is only for the administrator user , so it is checking where it is administrator user or not .. ,is the http://loclahost accessible if the user in not the administrator user ?
We have a SSO solution with ADFS for logging into our web app, we also have standard setup that uses authentication with our database. I want to setup a solution that allows for both. So now I am trying to figure out, is there any way for ASP.NET to detect if a user is authenticated with Active Directory so I could do this on the fly? If user is logged in through AD, send through ADFS, else, show login screen. Any idea?
I also realize that this may not work if they are setup to use forms based authentication only after the ADFS process is started.
Yes... In IIS, enable both integrated authentication, basic, and anonymous. All the real work is done in HTTPModule that are registered in the root Web.config (e.g. in the runtime CONFIG folder). The built-in Authentication HTTPModule will set the user Principle once authenticated if authenticated via integrated credentials. You can add your own to be fired after it. If the IIdentity (e.g. User.Identity) has the IsAuthenticated set to false then you know they were not authenticated and can then redirect them. If it is set to true, you can then replace the IPrinciple with one that contains roles that are germane to your application.
My DBA requires all database access to be done through trusted domain account. This can be done if you set the web.config . This requires the user to login or to be on the domain for IE pass the credentials through. I want to impersonate a user by using code. I am using the code found in this knowledgebase article:
http://support.microsoft.com/kb/306158
It works great, I pass in the credentials, impersonate the user, then make the call to the database and data is returned.
The problem is if I go to another page, I lose my impersonated credentials. This means every time I make a call to the database I have to run the impersonate code.
If IIS can impersonate a domain user for all pages, then why can I not impersonate a user while using code?
It seems to be something with thread context switching. I have tried setting the alwaysFlowImpersonatingPolicy in the Aspnet.config file and it did not work.
http://msdn.microsoft.com/en-us/library/ms229553.aspx
Any suggestion? Is it even possible to do what I want?
Impersonation occurs at the level of the thread. Impersonation causes the access token of the thread, which is usually inherited from the process, to be replaced with another. The best practice is to revert the effect of impersonation and thus the token as soon as you are done with the operation(s) for which it was needed. The story is no different with IIS or ASP.NET. Each request is usually handled by a distinct thread so you will have to make each thread impersonate the user.
This means every time I make a call to
the database I have to run the
impersonate code.
So that is correct.
If IIS can impersonate a domain user
for all pages, then why can I not
impersonate a user while using code?
IIS does not do it any differently and so it may only be a perceived illusion. It cannot impersonate a user for all pages unless all pages are being served by the same thread and where the impersonated token has never been reverted as each page is served.
It seems to be something with thread
context switching.
Not really. Unless you are doing asynchronous processing (which you don't state you do in your question), the flow of the impersonation context won't be relevant. You only need to worry about flowing the impersonation context if you are causing a thread switch either directly or indirectly during the processing of a single request. If you want that the work done by a secondary (worker) thread continues to occur under the impersonation context of the primary one then you need to make sure the secondary thread borrows the impersonation token. In .NET Framework 1.1, you would have to take great care and manually orchestrate the flow of the impersonation context. With .NET 2.0, however, the ExecutionContext API was introduced and does a lot of the heavy-lifting.
The reason you're losing the impersonation context is because each time a new page request ends the impersonation context will go out of scope.
As per the docs <alwaysFlowImpersonationPolicy> is used to ensure the same impersonation context is maintained across async calls. For example when making an async call to a remote web service the callback impersonation context is the same one as the initiating thread. In the case of ASP.NET the impersonation context would only flow for the lifetime of the page request.