WCF 4.0 Cookie Only First is Recorded by Browser - wcf

I am working on the fastest way to write cookies from a WCF self hosted console app REST service with WebHttpBinding.
I prepare the "Set Cookies" but only the first cookie is set in the browser (using FireFox 11.0 on Windows) as well as the "Expires" value.
var expiry = DateTime.Now.AddMonths( 6 );
var outresp = WebOperationContext.Current.OutgoingResponse;
outresp.Headers.Add( HttpResponseHeader.SetCookie , "cookie1=fd9416ea-2705-4d44-be76-f2f7b95e6b13; cookie2=7d489e69-d9c9-4b8d-a4b1-bce0da1c5966;expires=" + expiry );
I also tried putting a comma between the first cookie and the second one, that did not work either:
outresp.Headers.Add( HttpResponseHeader.SetCookie , "cookie1=fd9416ea-2705-4d44-be76-f2f7b95e6b13;, cookie2=7d489e69-d9c9-4b8d-a4b1-bce0da1c5966;expires=" + expiry );
I cut this down, and fired up Fiddler:
outresp.Headers.Add( HttpResponseHeader.SetCookie , "foo=foovalue;,bar=barvalue;" );
and Fiddler shows this:
Response sent 27 bytes of Cookie data:
Set-Cookie: foo=foovalue;,bar=barvalue;
This response did not contain a P3P Header.
Validate P3P Policies at: http://www.w3.org/P3P/validator.html
Learn more at: http://www.fiddler2.com/redir/?id=p3pinfo
Which tells me that I am not formatting things on the .NET side to make the cookies acceptable to the browser.
How can I get all of the cookies into the browser insetad of just the first value? What did I miss?
Thanks.
[ EDIT ]
I took the issue to Microsoft for support, and learned this:
The fact that "Set-Cookie" is munged into a single cookie line is logged as a bug within Microsoft for .NET Framework 4.0 and also Framework 4.5.
Within the Microsoft WCF development group, the bug is listed as "closed" and "won't fix".
According to Microsoft, the only workaround is to move from self-hosted to hosting within IIS and then using the (IIS) Response object directly (different code path that does not have the bug).

Although this is an older post, since this is still an ongoing issue and using the AspNetCompatibilityMode with WCF has significant performance downside, the option that MSFT has supplied is not viable under many/most/any circumstances. I'm going to answer this question late since this issue is still lingering.
The only way to resolve this issue is to output the Set-Cookie response header just as you've shown, but to process that response header on the client side with javascript and place it in to the browser since, as you've noted, the browser will not handle this response. Neither will applying more than one Set-Cookie response header work as noted in this bug I created.
http://connect.microsoft.com/VisualStudio/feedback/details/779111/wcf-rest-service-two-set-cookie-http-headers-invalid-set-cookie-header-syntax
So, process the response header and use document.cookie in client-side javascript to place the cookies in the browser within the success handler of your jQuery .ajax request.

To expand on #jeff-fischer 's answer, AspNetCompatibilityMode does work and requires the following:
AspNetCompatibilityRequirements is set for the service class to either Allowed or Required e.g.:
[AspNetCompatibilityRequirements(RequirementsMode
= AspNetCompatibilityRequirementsMode.Allowed)]
public class AppService : IAppService
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> is set in <system.serviceModel>
This then gives access to HttpContext (you'll need using System.Web; to get access to this) and cookies can be set using:
var aCookie = new HttpCookie("foo")
{
HttpOnly = true,
Value = "bar",
Expires = DateTime.Now.AddDays(1)
};
HttpContext.Current.Response.Cookies.Add(aCookie);
This will then need to be run as an application on IIS rather than though the WCF launcher and if multiple cookies are set, multiple cookie headers will actually appear.

Related

REST API and Identity Server 4 testing with Postman

I have a solution that has my web application, my REST API, and my Identity Server 4. All of which are now on .net 5. Locally everything works fine, but once I load everything up to the server, I get an error on Postman.
Setup - The API, and the IDP server are on separate sites.
What I Know - I know the IDP server works because I can get a token in Postman. I also know that the actual API works because when I remove the [Authorize] attribute from the controller I have, the call from Postman works fine.
The Problem - The problem that I have now is that when I put the [Authorize] attribute back in, I always get a 401 Unauthorized error for the API call. Below is the Startup file portion that sets up the authentication:
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = "https://bob.com/API-IDP/";
options.ApiName = "BOBSAPI";
options.ApiSecret = "bobssecret";
});
I also know that the Configure portion, that the order of the Use***** is correct. I've also tried tweaking with the AppPool settings, in terms of "Load Profile", all based on things I've found while searching. I've gone to the Identity 4 website and followed those examples as best as I can. Oh, one more thing. The IDP database has a table for PersistedGrants. I do see a few records in that table, which I think means the authentication worked? But if the authentication worked, then why did the API call return a 401? Is there something I need to do on the controller besides the [Authorization] attribute? I've spent 3 days on this and I'm pulling my hair out. Please help!
I would look at the response headers of the response from the API and see if this header gives any clues to why you are not authorized:
For example:
HTTP/1.1 401 Unauthorized
Date: Sun, 02 Aug 2020 11:19:06 GMT
WWW-Authenticate: Bearer error="invalid_token", error_description="The signature is invalid"
You should also make sure this flag is set to True in the AddJwtBearer config:
//True if token validation errors should be returned to the caller.
options.IncludeErrorDetails = true;
You can use a tool like Fiddler to do that.
Then I would look at the ASP.NET Core logfile to determine why it does not accept your token.
It took a bit, but with some help from Tore Nestenius, I was able to figure it out. Here's what I did with my final testing to get things working:
I used my Identity Server 4, hosted on our test server, as the authority. Then, I fired up my local API, so I could see the console. I was successful in getting the token, but when I went to request data through Postman, I got the same error about being unauthorized. I looked at the console and the error in the console basically said that the authority did not match what it was expecting. The difference turned out to be a forward slash. Once I made them match in my startup file, the API command worked.
The moral of the story here is make sure the authority you set up in your startup file is correct. If you are getting unauthorized issues, I would look there first.

Postman Resolving "Invalid CORS request" for a POST Request

I've just started using Postman to test an API I am integrating to.
I have the following error that keeps showing up
Invalid CORS request
Note the following:
The API uses Bearer token authentication(OAuth2). I have this
working without a problem.
I do get the bearer token successfully, assign it to an Environment variable and then attempt to use it for the RESTful operations.
The problem is in the subsequent RESTful operation that uses the token.
When I use an old token (through a POST operation), it rightfully
tells me that it is expired and not authorized.
When I then generate a new one and try to run the restful call, it gives me that Invalid CORS request error.
Using cURL, I have no issues. But I am frustrated by Postman.
What I have found so far:
Using postman with Http POST requests - I don't get the part in bold
Just in case anybody else has this same problem, here is how to solve
it. Go to https://www.getpostman.com/docs/capture in your chrome
browser. Click on interceptor extension and then choose add to
chrome. Once it is added there is a new icon top right of both the
browser and postman that looks like a traffic light. In postman click
this and it turns green. Then add a header to every request going to
third light. Every header consists of the header name and a value.
Start typing over the header name and a list of allowed http headers
comes up. Choose "Origin". In the cell for value simply type the
full URL of your server. (Do not forget the 'http://' or 'https://').
What is the expected response to an invalid CORS request? - Best explanation I have seen so far on CORS errors.
The other material speaks about Access-Control-Allow-Method header, preflight requests
... and there is an illustrative Apache Tomcat flowchart of the CORS flow.
Here's the answer you found again:
Just in case anybody else has this same problem, here is how to solve it. Go to https://www.getpostman.com/docs/capture in your chrome browser. Click on interceptor extension and then choose add to chrome. Once it is added there is a new icon top right of both the browser and postman that looks like a traffic light. In postman click this and it turns green.
... With the bit in bold translated:
Then add a header to your request. The header Key should be "Origin" and the header Value should be the full URL of your server (Do not forget the http:// or https://).
Note that Chrome/Postman won't allow you to add a Header with a Key of Origin without the Interceptor plugin.
Also note that at least on my system the Interceptor icon no longer looks like a traffic light.
If your back-end service side code checks for origin of the request (just to avoid CORS attack) you may face this issues when testing your Rest API through postman.
How to Resolve this .?
You need to install a Chrome plugin called Postman Interceptor (https://chrome.google.com/webstore/detail/postman-interceptor/aicmkgpgakddgnaphhhpliifpcfhicfo?hl=en).
After successfully installing this plugin , in you Postman client you can see small icon called Postman Interceptor , you need to toggle it to turn it on.
Now you can add a Request header as below
RequestHeader Key "Origin"
RequestHeader Value "your application base URL"
Check this image
Now you should be able to over come CORS issues you are facing
Cheers !!
Just avoid using browser/chrome postman plugin. Use the desktop application instead!
Seems our server is seeing from a Postman manual HTTP POST that the orgin is invalid b/c its coming from Postman as "chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop"
Not sure why or how to resolve on client/Postman side. Seems our server is correclty rejecting it as is though and issuing a 403.
Value of "Origin" header set in Postman request should be allowed in API backend. For example, using Spring Boot for API should have next:
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Value("${cors.allowedOrigins}")
private String allowedOrigins;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins(allowedOrigins)
.allowedMethods("*")
.allowedHeaders("*");
}
}
where allowedOrigins is set using application.properties property cors.allowedOrigins having comma separated list of allowed origins, eg:
cors.allowedOrings=http://localhost:8080,http://example.com
and set 'Origin' value in Postman to any url from cors.allowedOrigins
I was getting this error when testing my APIs on the postman. Even after meticulously configuring my cors. So I used Insomnia instead of Postman and it works fine. I guess sometimes postman is the problem as it needs some extra effort.
You can try new version of PostMan. To me it works after upgraded postman version from 5.5.5 to 7.36.5

WSO2 API Manager is not responding to a request that returns zip file (application/octet-stream)

Using WSO2 API Manager 1.3.1. Trying to use the API Manager to proxy to a REST service. I have set up the service in API Mgr and can successfully post and get responses, typically json, though some are text.
However, when I try to GET a resource that returns binary content (a zip "file", content-type:application/octet-stream), the API Manager does not seem to respond and I can see an error in the console window (i'm running wso2server.bat in console):
[2013-07-03 11:52:05,048] WARN - SourceHandler Connection time out
while writing the response: 173.21.1.22:1268->173.21.1.22:8280
I have an HTTPModule on my internal service and it seems to be responding with the appropriate content (I can see the GET and response data logged). I can also call to the internal service directly and get a response, so that end of things seems OK. But going through the API Manager seems to fail.
I found information on enabling other content-types:
WSO2 API Manager - Publishing API with non-XML response
http://wso2.com/library/articles/binary-relay-efficient-way-pass-both-xml-non-xml-content-through-apache-synapse
Using that information I tried to enable the application/octet-stream for messageFormatter and messageBuilder using the binary relay and it did not help (or seem to make a difference). I have even disabled all other content-types and use the binary relay for all content-types and it does not help.
Currently, I'm running with just the following in both axis2.xml and axis2_client.xml (in their appropriate sections):
<messageBuilder contentType=".*" class="org.wso2.carbon.relay.BinaryRelayBuilder"/
<messageFormatter contentType=".*" class="org.wso2.carbon.relay.ExpandingMessageFormatter"/>
I still get my json and text responses, but WSO2 times out getting the zip content. I saw the JIRA referenced in axis2.xml about enabling the ".*" relay, but as the other requests seem to work, I'm not sure it's an issue for me. I did try adding
'format="rest"' to the API definition, but it seemed to break all operations even the ones that worked prior so I've pulled it back out.
Any ideas on what is happening or how to dig in and debug this will help. Thanks!
After working with this for much too long, it turns out that my WSO2 configuration was correct, using the Message Relay and BinaryRelayBuilder, etc. While my REST service could reply immediately, I was setting a HTTP header that I assume WSO2 does not like, because when i removed it WSO2 would reply at an expected rate (instantly).
I was setting the header:
Transfer-Encoding: binary
When I removed that header from my service reply, then WSO2 operated as expected. I don't know if that's a "bug" in WSO2 or if I was implementing incorrectly, but I do have what seems like a "workaround" by omitting that header from my service response.

WCF - JSONP Content-Length Issue

Scenario:
Web Service needed to calculate values and send results back as json. These calls are to be made cross-domain so I'm using jsonp. The problem I'm having occurs both on the same domain and cross-domain.
Problem:
I'm having an issue getting back json data from a WCF Service. While on my local machine it works fine, but when on the server the response from the service is cut short (if I run it through Visual Studio on the server though, it's fine).
The content length seems to be set as the length of my response before wrapping it in the jquery callback function (example data below).
Local: jQuery151017220264650085249_1309423933796({"d":"[\"Flat\",\"Terrace\",\"Semi\",\"Detached\",\"Bungalow\"]"});
Local: jQuery151017220264650085249_1309423933797({"d":"[\"New build\",\"2000 to 2010\",\"1990 to 2000\",\"1970 to 1990\",\"1950 to 1970\",\"Pre 1950\"]"});
Live: jQuery1510246237260361726_1309424024004({"d":"[\"Flat\",\"Terrace
Live: jQuery1510246237260361726_1309424024005({"d":"[\"New build\",\"2000 to 2010\",\"1990 to 2000\",\"1970 to
To wrap the json response with the callback function I had to use a httpmodule I found on the net.
The server uses IIS 7.5, locally i'm just using Visual Studio. (Some kind of IIS configuration?)
Right, hopefully I've provided enough information, if not let me know.
So if anyone has any idea how I could fix this issue it would be greatly appreciated.
Thanks
You don't need to use an HTTP Module to wrap the response in JSONP - this feature is available in WCF 4.0. You can set the property CrossDomainScriptAccessEnabled in WebHttpBinding, and if the request comes from a different domain (and it has a ?callback=FunctionName) parameter, the response will be wrapped in FunctionName(...).

Calling WCF/JSON/REST WebService from JavaScript using jQuery/Ajax

I know there are a lot of questions out there about this - believe me I've read a lot of them and tried the answers out.
(This project is for an internal company lan, not the internet)
We have a WCF webservice which is RESTFUL and sends/receives JSON, it requires NTLM (Kerb would also be good) auth/credentials to ensure that the calling user (from the browser is who they say they are), and this is negotiated between the browser/client and the service by the WCF bindings:
<bindings>
<webHttpBinding>
<binding name="webHttpBindingAuth">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm"/>
</security>
</binding>
</webHttpBinding>
</bindings>
Using Fiddler, I can call the methods on the service GET and POST successfully and provided I adjust the JSON we're sending to the webservice (to include the session ID for example) it trundles along happily.
The problems started when we tried to use JavaScript/jQuery to call the webservice; the idea is that a web server will supply the HTML/JS to the client browser, the browser should then call the WCF webservice to get a session and allow a user to perform a few actions (we have 3 methods in total).
Firstly, we ran into the X-Domain issue, which we tried to resolve by getting the web server to return the correct headers (Access-Control-Allow-Origin). This didn't prevent browsers like SRIron from telling us that;
XMLHttpRequest cannot load http://{webServiceUri}/InstantMessagingService/chat/start/{username}. Origin http://{web**Server**Uri} is not allowed by Access-Control-Allow-Origin.
Following this, I investigated the possibility of using Silverlight (doesn't seem to support NTLM auth over WebHttpBinding), reverse proxy is out, as the IIS server being used in dev won't be used in prod (I believe it is WebSphere, but not under our control); next I looked at this:
http://msmvps.com/blogs/paulomorgado/archive/2007/04/27/wcf-building-an-http-user-agent-message-inspector.aspx
Which left me under the impression that the WCF web service was in fact the thing that needed to tell the browser where it was allowed be called from (if that makes sense). Having implemented all the code from the example, I found that the ApplyClientBehavior was never called to attempt to return the headers to the client (monitoring this in Fiddler too). Some more Googling led me to:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/707aa031-f4ff-47ab-ba5b-730f7930605e/
Since we're accessing the web service using jQuery and not some .NET client/service reference/proxy/app.. blah, I'm thinking that it's not possible to pre-request-send these headers to allow access to the service. Also, Fiddler seems to think that it's getting a 401 Unauthorized when it does make the attempt to call the http://../chat/start/.. method.
Here's the jQuery I'm using to attempt to make the call (I supplied a few settings in the hope it was going to work):
var url = webserviceUrl + "chat/start/" + remoteUserUri;
$.ajax({
type: 'GET',
url: url,
crossDomain: true,
beforeSend: function(xhr){ xhr.withCredentials = true; },
contentType: "application/json; charset=utf-8",
success: function (data) { conversationStarted(data); },
dataType: 'json'
});
Ok, if anyone has helpful hints or ideas, please fire away. I'll reply and edit etc. to make sure this is kept up to date, I hope I haven't missed anything (but my heads spinning a little from my Googling).
Also, I know that there might be better ways to do this, but I'd like to do it in the cleanest/quickest way from where I am now - i.e. not a lot of code changes, rewrites etc. I can also post up configs if people think they really are useful.
In the end I had to kind of work around, we got the guys in charge of the web server to agree to serving up an IFrame which points to our IIS hosted page (the one containing the JS etc.)
Then using the magic of WCF/Windows we host the WCF services on port 80 which gets around the X-Domain origin stuff. So I can then have REST/JSON without having to use JSONP.
I know it's not the answer to the question given the criteria I specified, but I think I ran out of options completely in the end.
Can you use JSONP? It'll solve your cross-domain problem in a heartbeat.