WCF AND ASP.NET session sharing - asp.net

Here is my case, I am working on an infrastructure for a scale able application.
I am creating a simple ASP.NET client page that consumes a WCF service with an AJAX call (simple xmlhttp object not .net script manager).
I need the 2 to share sessions, so I have instructed the ASP.NET client application to store the session in SQL with the aspnet_regsql.exe tool.
I have checked that WCF service is receiving the same session ID that the ASP.NET client produces, but in the service the session keys container is empty.
I am under an impression that it might have something to do with the app name in the configuration, but I really don't know...
Any direction ?

If you must share ASP.NET session with WCF services, you need to check out WCF Services and ASP.NET on MSDN to find out how to enable the WCF ASP.NET compatibility mode.
Mostly, it boils down to:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
in your WCF service's service-side config. Also, you must make sure your WCF service implementation doesn't explicitly deny the ASP.NET compatibility mode.
So your WCF service class must either allow or even require the ASP.NET compatibility:
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class YourService : IYourService
or
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class YourService : IYourService

I have found the answer to my problem.
I needed to change the "TempGetAppID" procedure in the SQL ASPState DB created with the "aspnet_regsql.exe" tool to take the APP_NAME() and not the passed argument.
That made sure that all application now share the same session.
once I have made the change the WCF Service has started to be aware of sessions inserted in my asp.net application.
problem solved.
ALTER PROCEDURE [dbo].[TempGetAppID]
#appName tAppName,
#appId int OUTPUT
AS
SET #appName = APP_NAME()
SET #appId = NULL
SELECT #appId = AppId
FROM [ASPState].dbo.ASPStateTempApplications
WHERE AppName = #appName

Related

WCF request doesn't flow via asp.net pipeline

I have a WCF service hosted in an asp.net application.
Here's the service (shortened):
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceContract(Name = Name, Namespace = Namespace)]
[ServiceBehavior(Name = Name, Namespace = Namespace)]
public class WcfMaintenanceFacade {...}
Here's hosting:
RouteTable.Routes.Add(new ServiceRoute("entity/maintenance/5.20", new ServiceHostFactory(), typeof(WcfMaintenanceFacade)));
And here's relevant config section:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
My service instantiates, the requests are coming in, and event HttpContext.Current is not empty.
There are two (major, for me) issues that I can't solve:
HttpContext.Current.Session is empty
Global.asax's Application_BeginRequest is never called
And yes, from the call stack it seems like the request is going through WCF activation pipeline, not ASP.net pipeline. So what am I doing wrong?
About the session, you handle it with OperationContext.Current.RequestContext instead of HttpContext.Current.Session.
HttpContext: Current is always null when accessed from within a WCF
service. Use
T:System.ServiceModel.OperationContext.Current.RequestContext instead.
Read more here: https://msdn.microsoft.com/en-us/library/aa702682.aspx
Application_BeginRequest are used by ASP.Net applications, but WCF works different from common web applications, thus BeginRequest could not be hit on each request.
The ASP.NET HTTP runtime handles ASP.NET requests but does not
participate in the processing of requests destined for WCF services
.... he WCF Service Model intercepts messages addressed to WCF
services and routes them through the WCF transport/channel stack
So, your problem can be related to this issue. This information is also available at the same link.
Hope it helps with your questions.
And the answer is simple (and, well, obvious):
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
Yes. RAMMFAR.
For me it is clear that these two technologies are not supposed to be working in the same application, and that's why they have two different pipelines. Service by the nature is an isolated thing. Now you just try to find a workaround, relying on the fact they both work on same IIS.
I would recommend you rather start from the goals, from what you want to achieve. If you need new service-like functionality integrated into native ASP.NET application you can
1) use ASMX services (will give you SAOP if you need it) and/or page methods
2) try to integrate WEB API in case you need JSON service.

Forms Authentication Cookie and WCF

I have an asp.net 4.0 application (client) that makes ajax/json calls to a http facade that then passes on the calls to our wcf service layer.
Users must authenticate on the client using forms authentication. The idea then being that the authentication cookie will be passed to and be accessible at the http facade. [Design based on Dino Esposito's book - Microsoft ASP.NET and AJAX: Architecting Web Applications]
The problem is, that at the facade, HttpContext.Current.User.Identity.Name is an empty string and IsAuthenticated is false.
I have enabled compatibility by adding the following to my system.ServiceModel section in my web.config (http facade level):
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
I have decorated my service with the following:
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Required)]
When I am debugging in the ajax/facade app I can see that cookies exist at HttpContext.Current.Request.Cookies. It appears that Anonymous is being used and not my authenticated user.
Both applications are running on the same IIS server.
Calls to the AJAX enabled wcf service are made via serviceProxy.js. Perhaps this method is not passing the necessary cookie?
WCF tracing is currently showing '..ASPXANONYMOUS=.....; ASP.NET_SessionId=....; .ASPXAUTH=.....' in the message log.
I get the feeling I am missing something simple but am too close to the problem.
Any suggestions welcomed.
I am not sure I completely understand the context of what you are trying to accomplish, but if these are two separate applications you are going to need to share machine keys in order to decrypt/encrypt the auth cookies in both.
in your web.config, make sure you have the following set:
<machineKey
validationKey="[generated key]"
validation="HMACSHA512"
decryptionKey="[generated key]"
decryption="AES"
/>
see how to generate these keys (and more info about them) on this codeproject article:
ASP.Net machineKey Generator - CodeProject
Let me know if this helps...

Access Session in WCF service from WebHttpBinding

I'm using WCF service (via WebGet attribute).
I'm trying to access Session from WCF service, but HttpContext.Current is null
I added AspNetCompatibilityRequirements and edited web.config but I still cannot access session.
Is it possible to use WebGet and Session together?
Thank you!
Yes, it is possible. If you edit the web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
and add the AspNetCompatiblityRequirements, the HttpContext.Current should be available.
Check everything once again, maybe you've put the attribute in the wrong place (the interface instead of the class?).
A RESTfull service with a session?
See excellent discussion here: Can you help me understand this? "Common REST Mistakes: Sessions are irrelevant"
http://javadialog.blogspot.co.uk/2009/06/common-rest-mistakes.html (point 6)
and
http://www.peej.co.uk/articles/no-sessions.html
Quote from Paul Prescod:
Sessions are irrelevant.
There should be no need for a client to "login" or "start a connection." HTTP authentication is done
automatically on every message. Client applications are consumers of
resources, not services. Therefore there is nothing to log in to!
Let's say that you are booking a flight on a REST web service. You
don't create a new "session" connection to the service. Rather you ask
the "itinerary creator object" to create you a new itinerary. You can
start filling in the blanks but then get some totally different
component elsewhere on the web to fill in some other blanks. There is
no session so there is no problem of migrating session state between
clients. There is also no issue of "session affinity" in the server
(though there are still load balancing issues to continue).

Can't get FormsAuthentication to properly work with WCF

I have both the wcf and asp.net project together in the same project. (I'm running on Azure, so this is more convenient).
I have this set in the web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
My wcf service is decorated with:
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
With those attributes set, shouldn't the HttpContext.Current.User be automatically set for me when I run methods in my wcf service? Currently, HttpContext.Current.User is null and not being set for me automatically.
I thought if I used aspNetCompatibilityEnabled then the Application_AuthenticationRequest method would fire in the Global.asax when the wcf method is executed, but, it does not.
The .aspxauth cookie is getting correctly passed to the wcf service, and I'm able to manually decrypt the cookie and set the current user.
Suggestions of why this is not working the way I expect?
Are you getting the expected user identity in the
ServiceSecurityContext.Current.PrimaryIdentity
field which is available inside your server method's code?? It should be some form of an IIdentity descendant giving you the user info, if available.

ASP.NET Impersonation and SQL Server Trusted Connection Calls

I am working on an ASP.NET page that we, in code impersonate the requesting user. We are using the following code to start impersonating.
Dim impersonationContext As System.Security.Principal.WindowsImpersonationContext
Dim currentWindowsIdentity As System.Security.Principal.WindowsIdentity
currentWindowsIdentity = CType(User.Identity, System.Security.Principal.WindowsIdentity)
impersonationContext = currentWindowsIdentity.Impersonate()
After this we have validated that the application is running under the proper context by calling:
System.Security.Principal.WindowsIdentity.GetCurrent().Name
This returns the proper identity of the user, and file access and other items appear to be using their account. However when using the Microsoft Application Data Application Block SqlHelper class to call out to a database using a trusted connection authentication fails for the "NT AUTHORITY\ANONYMOUS LOGON" user.
We can re-validate after the failure that the current identity is still our desired account and NOT the ANONYMOUS LOGIN account.
Does anyone have an idea why this is? Or more specifically how we can get around it?
Edit
Some additional information about how the calls from these pages work.
We do the impersonate call from the .aspx page.
After we impersonate we call out to a "business logic" assembly that is referecned.
We know that the context identity is still correct here.
After that, the "business logic" assembly calls another assembly that actually executes the trusted connection call. We cannot modify this "data access" assembly, the authentication exception is reported by this assembly as well.
I think #John Sonmez is right, you're hitting the Double Hop issue. Impersonation is only half of the story, you also need to look at Delegation (assuming your network is using Kerberos authentication). The articles below were the most useful in helping me through the same issue
Impersonation and Delegation
ASP.NET Delegation
I know that I've used impersonation in ASP.NET before (using C# and accessing the filesystem) and I was wondering if you had tried wrapping the logic that includes currentWindowsIdentity.Impersonate() with a 'Using / End Using' (to explicitly define the security context for a block of code).
So, it would look like this:
Using impersonationContext = currentWindowsIdentity.Impersonate()
' Logic here
End Using

Resources