Impersonation using httpmodule, threading issue - asp.net

We have as SAAS application that runs for multiple customers at the same time. All customers use the same application, and by checking the URL used to access the application, users are redirected to the correct data for the organization.
Underwater, every organization has their own database. To make sure that users don't accidentally end up in the wrong database, we want to impersonate the request being executed to a user that only has access to the correct database. We used to do this and this worked beautifully on IIS in classic mode.
However, in integrated pipeline mode, we run into a threading issue. We use an HTTP module to impersonate the request to the correct user in the "PreRequestHandlerExecute" event. The problem that (apparently) there is no guarantee that this method is executed in the same thread as the handler that actually processes the request. This causes the impersonation to sometimes not work because the thread processing the request is not impersonated.
I've created a test project in GitHub (https://github.com/PaulVrugt/ImpersonationExample/tree/master/ImpersonationTest) demonstrating the issue (apologies for the vb.net, but you'll get the idea). When you run the example connected to an IIS using integrated pipeline mode, you'll see that sometimes the impersonated user is not used, and each time it is not used, the managedthreadid of the thread processing the request is different from the thread used in the httpmodule.
Now that I understand why it "sometimes" doesn't work, I begin to suspect I'm going about this all wrong. Is there a way to achieve what I am trying to do?
We've already tried to impersonate in the prerequesthandler in the global.asax, but that results in the same issue.

Related

Spring Boot with Embedded Tomcat: Session not persisting through restart

The research I've done on this seems to indicate that this should happen automatically. Some writings suggest that it is required to place server.session.persistent=true inside src/main/resources/application.properties. I have done this and I believe sessions are still not persisting.
Some background: Using Spring Boot with embedded Tomcat and Spring MVC + Thymeleaf. The user "logs in" to my application using their google account. Once they are authenticated by Google, my application gives them a unique identifier which is stored as a property inside the user's HttpSession. This property is of type Integer. I do have an H2 database hooked up to this application but from what I've read I should be able to solve this problem without having to worry about storing sessions in the database.
When I launch the application using gradle (bootRun), I receive a cookie with my JSESSIONID as expected and I login with my user. The user can navigate to different pages in my Spring MVC application and they are still 'logged in' by virtue of the session attribute being set on the server side. When I stop the process in my IDE (to my knowledge this is not the same as terminating it) and restart it, then visit my application again in the web browser, I am immediately issued a different JSESSIONID.
It seems to me that the immediate problem is that my session is not being remembered between server restarts. I have seen some writings that hint at implementing my own 'session store' or something like that, but I assume that first it is necessary for the server to understand that this is the same session.
I'd be happy to provide more information that would help, thanks everyone who took the time to read this.
Final Notes:
I am not using Spring Session or Spring Security, at this point I don't anticipate needing to for this project.
This is a "prototype" application for my own personal use, so feel free to warn about design issues but it is not my intention to make it bulletproof from a security perspective.

Token From Different Server Causing Continuous Crashes

We have an ASP.NET Core application which has the default authentication system and is hosted on Azure.
Recently, we created a new AppService and routed the users to that service while maintaining connection to the same database.
However, when users use the new server, we get continuous crashes with the following error:
The key {xxx-xxx-xxx-xxx} was not found in the key ring.
of type
System.Security.Cryptography.CryptographicException
and method
Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(String
serializedToken)
Our understanding is that the server is trying to decrypt the token but since it was received from a different server, our server just crashes.
We would so much appreciate if you can suggest a way to solve this issue temporarily until we change the DataProtection provider.
We want a way that wouldn't let our server crash.
Thank you so much
Update: I'm surprised now that this error happens in: POST Account/Login and POST Account/Register while these methods do not require authorization, however these methods are decorated with:
[ValidateAntiForgeryToken]
Both Get Account/Login and Post Account/Login happen on the same server.
Make sure you have machine key same across the farm. You should set it at the application level, meaning, different apps have different keys but the same app has the same key on all server of the farm.
The machine mey is responsible for encrypting some internals of selected features of the engine, including the antiforgery tokens. A different key on different servers causes the exact issue you describe.
https://blogs.msdn.microsoft.com/amb/2012/07/31/easiest-way-to-generate-machinekey/
https://msdn.microsoft.com/en-us/library/w8h3skw9(v=vs.100).aspx
In my case.
This error happened as I was using two or more instances for the identity server.
So,
Login goes fine but checking the token cause errors.
As the login was done by an instance and checking was done using other instance.
The easiest way to solve this is to make sure that your identity server or API is using only one instance.

Authenticate users syncing time out for 2 different sites

I have been puzzling over this and can't think of an good way of doing this. I am developing a website that would require the user to log in to use the system. I'm thinking of using ASP.NET MVC 4's built in authentication. That isn't much of a problem.
The user would be able to use tools on another server (our server would authenticate him and tell the other website, he is good to go, these messages are passed via HTTPS using XML). The other server, require us to create an authentication token for the user to use when the messages are passed between us.
We need to keep the token in our database to authenticate for every request/response with the other server. Which means that this "token table" knows nothing about the forms authentication time out on our server and vice-verse.
Now the problem, let's say the user uses the other server's tools. He would be on the other server for a long time, this would cause the authentication on our server to log him out, since there doesn't seem to be any perceived activity. The other server will not log him out since we are manually maintaining the token. This would be a troublesome for the user, because now, if he needs to use our service, he'll have to log in again even though he was "online" all the time.
Is there a way to "sync" the 2 authentications? At first I was thinking of getting our server to look up the "token table" (instead of using the built in authentication) so that if the last activity was x ago, the user will be required to log in again, this would solve the untimely logging out from our server. But I'm worried about the security implications.
What would be the best way to do this?
Thank you.
Desmond
If I've understood you correctly you are using Forms Authentication in an MVC4 application to authenticate users, but users will also use another web service located on a different server and so while they are using this other server you don't want the MVC4 application's authentication (for the user) to timeout. Is that correct?
If so, one idea that comes to mind is that your MVC4 application could have an API to the external world that would take in a username and use RenewTicketIfOld() to refresh the timer associated with the ticket. You could do this via the other web server making an HTTP request or by simply placing some AJAX on the page to call the API on every page.
There are, of course, security concerns with this method that you would need to consider. Without knowing more about your situation I'm not sure what solution would be best.

Call COM DLL functions from ASP.NET project as specific user

I am trying to call an old VB6 dll (no source code available) from an ASP.NET project. The dll connects to a server using windows authentication, so I need to call functions as a specific user, not NETWORKSERVICE as it is now.
This would preferably be determined at call time, not load time because I am impersonating the remote user and would like for this to be the user calling the functions, not the application user and not NETWORKSERVICE as it is now.
So, theres the browser running as USER, connecting to the application impersonating USER, calling the dll as USER, but the dll is trying to connect to a remote server as NETWORKSERVICE, not USER.
Is it possible to make this dll connect to the remote server as USER? Or, if nothing else, connect as the application user?
Edit:
Impersonation is done in code by calling Impersonate() on the remote user's WindowsIdentity. The company I work for has a custom SecurityPrincipal and SecurityIdentity so it's kind of weird how I have to go about getting the WindowsIdentity (it's a little more in depth than User.Identity), but I have used this method before successfully and have verified that System.Security.Principal.WindowsIdentity.GetCurrent().Name
is the correct user during the impersonation.
I would first try to find out how the DLL is connecting as a different user (Process Explorer can help with this). Is it possible that the DLL is communicating with a service (or some other process) which is running on the box which is logged in as NETWORKSERVICE? If so, you can change that service to run as a different user. Just grasping at straws, hope you figure it out!
I did eventually find the problem (which just lead to other problems, but anyway) it turned out to be I was missing an AspCompat="true" on my page. Actually the problem was that I was using a "Handler" and not a "Page". Handlers do not have the STA abilities that Pages have. What was happening was every time I tried to access the COM component, there would be a thread switch (impersonation lost) since the application is running in an MTA and the COM component must run in an STA.

Impersonating a User in Asp.Net

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.

Resources