Pass message headers on WCF via netTcpBinding - asp.net

After banging my head for a day I'm asking for help. I have a Web Forms application with WCF service hosting at the same machine. The WCF service has methods with some sort of custom permissions (for instance, only "admin" can set passwords for users).
Web forms app uses Forms Authentication so I have HttpContext.Current.User with all the roles this uses has. So I used an AuthCookie to pass the object via HttpRequestMessageProperty and read it like this:
HttpRequestMessageProperty property =
OperationContext.Current.IncomingMessageProperties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
With basicHttpBinding that worked fine. But then I needed to implement net.tcp protocol so the HttpRequestMessageProperty doesn't work anymore. I've tried to add it by MessageHeader but that doesn't work either.
OperationContext.Current.IncomingMessagePropertieshas got none of my headers...
So how can I pass the user roles list to my WCF? I am using Windows security like this but I need to pass roles from HttpContext.Current.User:
<netTcpBinding>
<binding transactionFlow="True">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>

OK so I found the working way for transferring the role info. Although this is still unclear why standard ways didn't work for me here is the right one (thanks to Guy Burstein):
Client:
MessageHeader<string> header = new MessageHeader<string>(roleData);
MessageHeader untypedHeader = header.GetUntypedHeader(ProjectParam.Role, "justASampleNamespace");
OperationContext.Current.OutgoingMessageHeaders.Add(untypedHeader);
WCF:
string roles = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>(ProjectParam.Role, "justASampleNamespace");
if(roles.Contains(ProjectParam.AdminLoginID))
{
//Now business logic comes
}
ProjectParam.Role is just an internal constant utilized for key and the second parameter is a sample string (MSDN says the "namespace")

Related

How to force soap header authentication for my scenario?

The problem is: I need to connect to a soap web service; generated by java code; using ASP.Net client via C# through MS Visual Studio 2013.
Try 1, The usual way:
I have added a web service reference using the wsdl and by assigning the credentials like:
Credentials.Username.Username = "test";
Credentials.Password.Password = "test";
When executing, the following exception is being encountered:
The login information is missing!
Try 2:
I have searched for similar problems like:
how-to-go-from-wsdl-soap-request-envelope-in-c-sharp
Dynamic-Proxy-Creation-Using-C-Emit
c# - Client to send SOAP request and received response
I had chosen to generate a proxy class using the wsdl tool, then added the
header attribute, but I have found the following note from Microsoft:
Note: If the Web service defines the member variables representing the SOAP headers of type SoapHeader or SoapUnknownHeader instead of a class deriving from SoapHeader, a proxy class will not have any information about that SOAP header.
Try 3:
I have tried to change the service model in the client web.config:
<bindings>
<basicHttpBinding>
<binding name="CallingCardServicePortBinding">
<security mode="TransportWithMessageCredential" >
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
Then added the credentials like the first try, but the following error appears:
MustUnderstand headers:[{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] are not understood
So, now I don't know what to do !
I have no control over the web service and I need to build a client that understands it.
Help Please!
The Soap Request template is the following:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="...">
<soapenv:Header>
<credentials>
<userName>someUserName</userName>
<password>somePassword</password>
</credentials>
</soapenv:Header>
<soapenv:Body>
<ser:someRequest>
.......
.......
.......
</ser:someRequest>
If the destination web service uses authentication, then just ASMX won't do, since it is not aware of authentication, encryption etc. You have 2 options:
Use Microsoft WSE: http://www.microsoft.com/en-us/download/details.aspx?id=14089
this is nothing but an extension of ASMX which makes it Security/Encryption aware. (and some other features) technically, you'll be adding a reference to the WSE DLL and your Soap Proxy will extend from the WSE SOAP Client instead of the System one.
once you do that, the proxy class will have additional username/password properties that you can use to authenticate properly.
set the properties and see the outgoing request using fiddler. if the header is not what you want (because of namespaces etc.), then you can write a custom outgoing message inspector and modify the soap request nicely.
The other option (preferred) is to use WCF.
ASMX and WSE are older than WCF. WCF tries to bring all the web service nuances under one roof. if you get a WCF service reference, it (svcutil.exe) will automatically create the proxy class and the right bindings for you. (mostly custom)
once you do that, try setting the user name and password.
if that doesn't work, (i have frequently struggled to generate the right soap header for remote java based services that require username/password authentication), you can define a static header chunk in the web.config/app.config, that'll be sent as part of every request.
e.g.
<client>
<endpoint>
<headers>
<credentials>
<userName>someUserName</userName>
<password>somePassword</password>
</credentials>
</headers>
</endpoint>
</client>

Consume SOAP based web service with https

I'm integrating af ASP.NET application, which must consume a 3rd party SOAP web service, which can only be accessed by HTTPS. I add a service reference i VS2012 with the HTTPS URL and VS find the service just fine. But when I use the proxy that VS create to use the web service, it uses regular HTTP.
I suspect that I should alter the binding in the web.config, but I can't seem to figure out what to do. How do I set up the web service to use HTTPS?
You need to make sure that the binding the client uses has security mode="Transport" set up (and that the client binding matches the server binding), something like this for example:
<binding name="yourClientSecureBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
and that the client indeed accesses the httpS:// address of the web service:
<client>
<endpoint bindingConfiguration="yourClientSecureBinding"
address="https://..."
... />
</client>
You are not providing any code, so for starters have a look at these posts: here (Microsoft developer network - Transport Security with an Anonymous Client) and here (Https with BasicHTTPBinding).

Share ASP.NET Session Id between WCF and a Silverlight Http client

I have a WCF service configured to use ASP.NET session state. I have tested this WCF service with a WPF client and the session state is maintained across the different web requests.
Now I am trying to use this same WCF service from a Silverlight app which uses the new Http stack independent from the browser. I need to use this stack in order to be able to understand our WCF service faults. My problem is that in this case we are not able to read from the responses the Set-Cookie header with the ASP.NET_SessionId cookie or set the Cookie header in the requests.
This is the binding from the Silverligth application:
<customBinding>
<binding name="customHttpBinding_IBasoaWebService" sendTimeout="01:00:00">
<binaryMessageEncoding />
<httpCookieContainer />
<httpTransport maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" />
</binding>
</customBinding>
And this is the binding of the WCF service:
<basicHttpBinding>
<binding name="basicHTTP" closeTimeout="01:00:00" openTimeout="01:00:00"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
receiveTimeout="01:00:00" sendTimeout="01:00:00" allowCookies="false">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None" />
</binding>
</basicHttpBinding>
In the Silverlight application we are using this code to read the Set-Cookie header in the response:
IHttpCookieContainerManager cookieManager = channel.GetProperty<IHttpCookieContainerManager>();
if (cookieManager.CookieContainer == null)
cookieManager.CookieContainer = new CookieContainer();
Uri applicationUri = new Uri(Application.Current.Host.Source, "../");
string cookieString = cookieManager.CookieContainer.GetCookieHeader(applicationUri);
ParseCookieString(cookieString);
And this is the code to set the ASP.NET Session ID cookie in the request:
IHttpCookieContainerManager cookieManager = channel.GetProperty<IHttpCookieContainerManager>();
if (cookieManager.CookieContainer == null)
cookieManager.CookieContainer = new CookieContainer();
Uri applicationUri = new Uri(Application.Current.Host.Source, "../");
Cookie cookie = new Cookie("ASP.NET_SessionId", aspNetSessionId);
cookieManager.CookieContainer.Add(applicationUri, cookie);
Checking through Fiddler the messages which are exchanged I see that the WCF service sends correctly the Set-Cookie header in the first response, but the Silverlight is not able to read it. I have also tried to set the Cookie header in the request through the CookieContainer class, but with no luck. I cannot see it in Fiddler.
Coould someone give me an advice about what I must be doing wrong?
Many thanks in advance.
Jose Antonio Arroba
In a web application, I use URI to set the SessionID. (I think it's possible with a WCF service)
In the web.config of your service, define :
<system.web>
<sessionState cookieless="true"></sessionState>
</system.web>
or
<sessionState cookieless="UseUri"></sessionState>
The sessionId appaears like this :
http://localhost:51358/(S(1wnqb23d2qe4blfxzukligdo))/default.aspx
You can get and set the SessionID in the URI.
Finally I have been able to find a workaround to solve this problem.
The reason why the Cookie header was not sent with the requests was that I was setting a bad Uri in the Cookie object. If I am trying to connect to http://localhost:8080/Service, it seems taht the correct Uri value to provide is http://localhost:8080 and not http://localhost:8080/Service.
However I am still wondering how to read the Set-Cookie sent by the server. My workaround consist on sending the ASP.NET Session ID also in a custom SOAP header and read it in the client, which is IMHO rather redundant. But it works.

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.

Public WCF service requires authentication, despite no security being specified

I have published a WCF service (MyService.svc) on an ASP.NET site, in a sub-folder called WebServices.
When running on the local ASP.NET web server it works fine. When published to an IIS-run site and I try to access, for example, /WebServices/MyService.svc/jsdebug, I get 401 Unauthorized. The rest of the site works fine.
Does anyone have any idea why?
Here are the contents of MyService.svc:
<%#ServiceHost
Language="C#"
Debug="true"
Service="MyApp.Core.MyService, MyApp.Core"
Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"
%>
MyApp.Core.MyService is a class implementing IMyService (which has the attribute ServiceContract and method declarations with the attribute OperationContract).
By default, a WCF service will do Windows authentication unless configured otherwise. I think the following should do the trick:
<bindings>
<wsHttpBinding>
<binding name="wsHttp">
<security mode="None"/>
</binding>
</wsHttpBinding>
</bindings>
..and configure your endpoint to use this binding config.
There are 3 possible places where the call is getting blocked:
The IIS Settings, check that anonymous authentication is enabled
NTFS File access settings, check that the user that is the identity of the application pool has read access.
the web.config, check that authentication mode is None.
All of the above are before it gets to what could be blocking it in the WCF configuration. But from your comment to blowdart it looks like you have not configured WCF security.
Check also your IIS log for 401 errors. And check if this post is relevant.
And what does the web.config say? Do you have authentication there, either on the service itself, or the directory? Is transport security on or off? Message security?
The svc files do not configure security, that's part of the config file

Resources