Duplicate Set-Cookie Headers from HTTPURLResponse - nshttpcookie

I am hitting an API to get a cookie for authenticating subsequent requests. I need to get the cookie from this collection of response headers:
{
"Server": "Cowboy",
"Connection": "close",
"Set-Cookie": "heroku-session-affinity=ADaDaANoA24IAXtpQOD///8HYgAAKehiAA6V12ECbAAAAAJtAAAABXdlYi4ybQAAAAV3ZWIuMWrNqkap0u4H0uG3Btrtlamaq2nQ5w__; Version=1; Expires=Wed, 11-Jan-2017 01:12:09 GMT; Max-Age=86400; Domain=xxxxxxxx.xxxx.xx; Path=/; HttpOnly",
"X-Powered-By": "Express",
"Vary": "Origin",
"Access-Control-Allow-Credentials": "true",
"Content-Type": "application/json; charset=utf-8",
"Content-Length": "30914",
"Etag": "W/\"78c2-veX2kgrO3zh118nYsOP80A\"",
"Set-Cookie": "connect.sid=s%3ACX3tfhPk9nlRtU8e8gtouQIx1kpP07h9.iExm%2F96Dgzuh289nmjwbYO49E0Bq0WwUHmN539IkudI; Path=/; Expires=Thu, 12 Jan 2017 01:12:09 GMT; HttpOnly",
"Date": "Tue, 10 Jan 2017 01:12:09 GMT",
"Via": "1.1 vegur"
}
I need to get the following cookie:
"connect.sid=s%3ACX3tfhPk9nlRtU8e8gtouQIx1kpP07h9.iExm%2F96Dgzuh289nmjwbYO49E0Bq0WwUHmN539IkudI; Path=/; Expires=Thu, 12 Jan 2017 01:12:09 GMT; HttpOnly"
I want to parse the headers and return that cookie, but the following code only displays the cookie that I don't want:
internal final class CookieParser {
internal static func cookie(from response: HTTPURLResponse) -> HTTPCookie? {
print("\n====> Response: \(response)\n")
guard let url = response.url else { return nil }
guard let headerFields = response.allHeaderFields as? HTTPHeaders else { return nil }
print("\n====> Headers: \(headerFields)\n")
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url)
print("\n====> Cookies: \(cookies)\n")
return nil
}
}
The code above produces the following output:
====> Response: <NSHTTPURLResponse: 0x60800002e160> { URL: http://xxxxxxxx.xxxx.xx/xxx/xx/xxxxx } { status code: 200, headers {
"Access-Control-Allow-Credentials" = true;
Connection = close;
"Content-Length" = 30914;
"Content-Type" = "application/json; charset=utf-8";
Date = "Tue, 10 Jan 2017 01:12:09 GMT";
Etag = "W/\"78c2-veX2kgrO3zh118nYsOP80A\"";
Server = Cowboy;
"Set-Cookie" = "heroku-session-affinity=ADaDaANoA24IAXtpQOD///8HYgAAKehiAA6V12ECbAAAAAJtAAAABXdlYi4ybQAAAAV3ZWIuMWrNqkap0u4H0uG3Btrtlamaq2nQ5w__; Version=1; Expires=Wed, 11-Jan-2017 01:12:09 GMT; Max-Age=86400; Domain=partners.flye.co; Path=/; HttpOnly";
Vary = Origin;
Via = "1.1 vegur";
"X-Powered-By" = Express;
} }
====> Headers: ["Content-Type": "application/json; charset=utf-8", "Content-Length": "30914", "Connection": "close", "Set-Cookie": "heroku-session-affinity=ADaDaANoA24IAXtpQOD///8HYgAAKehiAA6V12ECbAAAAAJtAAAABXdlYi4ybQAAAAV3ZWIuMWrNqkap0u4H0uG3Btrtlamaq2nQ5w__; Version=1; Expires=Wed, 11-Jan-2017 01:12:09 GMT; Max-Age=86400; Domain=partners.flye.co; Path=/; HttpOnly", "Vary": "Origin", "Etag": "W/\"78c2-veX2kgrO3zh118nYsOP80A\"", "Access-Control-Allow-Credentials": "true", "X-Powered-By": "Express", "Date": "Tue, 10 Jan 2017 01:12:09 GMT", "Via": "1.1 vegur", "Server": "Cowboy"]
====> Cookies: [<NSHTTPCookie version:1 name:"heroku-session-affinity" value:"ADaDaANoA24IAXtpQOD///8HYgAAKehiAA6V12ECbAAAAAJtAAAABXdlYi4ybQAAAAV3ZWIuMWrNqkap0u4H0uG3Btrtlamaq2nQ5w__" expiresDate:2017-01-12 00:41:08 +0000 created:2017-01-11 00:41:08 +0000 sessionOnly:FALSE domain:".partners.flye.co" partition:"none" path:"/" isSecure:FALSE>]
The unwanted Set-Cookie value must be replacing the wanted Set-Cookie value in the dictionary of returned headers. Is there a way that I can retrieve the wanted Set-Cookie value before it is replaced?

Related

Access-Control-Max-Age not working with Authorization header

Trying to workout why chrome is still firing prefetch request even though the Access-Control-Max-Age has been specified when combined with the Authorization header. If I remove the Authorization header preflight caching works as expected.
Request headers
:method: OPTIONS
:path: /v1/api
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-GB,en-US;q=0.9,en;q=0.8,pt-BR;q=0.7,pt;q=0.6,fr;q=0.5
access-control-request-headers: authorization,content-type
access-control-request-method: POST
origin: https://null.jsbin.com
referer: https://null.jsbin.com/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
Response headers
access-control-allow-credentials: true
access-control-allow-headers: *
access-control-allow-methods: OPTIONS,POST
access-control-allow-origin: *
access-control-max-age: 86400
content-length: 0
content-type: application/json
date: Wed, 04 Aug 2021 08:30:50 GMT
I'm slowly grinding through this doc https://fetch.spec.whatwg.org/#http-cors-protocol but can't see any reason why Authorization should block preflight caching.
Also, as an aside. If Authorization is incompatible with Access-Control-Max-Age is it such a bad idea to include the auth token in the body rather than as a header from a security point of view? You may assume, over TLS.
Server code: https://glitch.com/edit/#!/prairie-bright-earl?path=server.js%3A22%3A0
Client code: https://jsbin.com/dejetem/16/edit?js,console
For reasons that are not totally clear to me, specifying Access-Control-Allow-Headers: Authorization, * "fixes" things and the Access-Control-Max-Age: 10 is respected. The authorization header is an edge case which must be explicitly safe listed by the server
[0][1][2]
const buildHeaders = origin => {
return {
"Access-Control-Allow-Methods": "*",
// the key line 👇
"Access-Control-Allow-Headers": "Authorization, *",
"Access-Control-Allow-Origin": "*",
"Access-Control-Max-Age": "10"
};
};
fastify.options("/", function(request, reply) {
reply
.code(200)
.headers(buildHeaders(request.headers.origin))
.send();
});
fastify.post("/", function(request, reply) {
reply
.code(200)
.headers(buildHeaders(request.headers.origin))
.header("Content-Type", "application/json; charset=utf-8")
.send({ hello: "world" });
});
const url = 'https://dynamic-past-deltadromeus.glitch.me/'
const opts = {
headers: {
'Content-Type': 'application/json',
'Authorization': 'asdf'
},
method: 'POST',
body: JSON.stringify({ message: 'ping' }),
}
fetch(url,opts)
Source code:
Server source code https://glitch.com/edit/#!/dynamic-past-deltadromeus?path=server.js%3A8%3A0

.NET Web API 2 with CORS and Angular Not Working on First Post

I am using .Net ASP Web API V2 with Angular 1 and Auth0.
After initial login through Auth0 I am getting the following error:
XMLHttpRequest cannot load localhost:3001/profile. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:62379' is therefore not allowed access. The response had HTTP status code 500.
If I refresh I no longer get the error. If I clear the browser data I get the error again but get success after a refresh.
I have CORS enabled in the API config with the required NUGET packages.
I have tried the following solutions because I thought this was a pre-flight issue:
1) Handling the SELECT verb on the controller and globally by intercepting the request.
http://www.jefclaes.be/2012/09/supporting-options-verb-in-aspnet-web.html
2) Adding the select verb as one of the accepted verbs on the controller method.
3) Various answers I have found on here for changing the request.
** I can not share links my rep is too low.
etc.
4) Using a specific origin instead of *
The Controller:
[Route("profile")]
[EnableCors(origins: "*", headers: "*", methods: "OPTIONS")]
public HttpResponseMessage Options()
{
var resp = new HttpResponseMessage(HttpStatusCode.OK);
resp.Headers.Add("Access-Control-Allow-Origin", "*");
resp.Headers.Add("Access-Control-Allow-Methods", "*");
return resp;
}
[Route("profile")]
[EnableCors(origins: "*", headers: "*", methods: "POST")]
[HttpPost]
public object Post([FromBody]dynamic data)
{
string email = null;
var b = new object();
try
{
**** Logic ****
}
catch (Exception ex)
{
**** Return Error ****
}
return b;
}
API Config
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute(
origins: "*",
headers: "*",
methods: "*");
// Web API configuration and services
config.EnableCors(cors);
var clientID = WebConfigurationManager.AppSettings["auth0:ClientId"];
var clientSecret = WebConfigurationManager.AppSettings["auth0:ClientSecret"];
config.MessageHandlers.Add(new JsonWebTokenValidationHandler()
{
Audience = clientID, // client id
SymmetricKey = clientSecret // client secret
});
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
The Angular Request
function postLogin() {
var loginPackage = [];
if (token === null) token = store.get('token');
if (store.get('profile') != null) {
loginPackage = store.get('profile');
}
return $q(function(resolve, reject) {
$http({
method: 'Post',
url: BASE + 'profile',
data: loginPackage,
crossDomain: true,
xhrFields: {
withCredentials: true
},
contentType: 'application/json'
})
.success(function(data, status) {
*** Logic ***
resolve(function() {
resolve(true);
});
})
.error(function(data, status) {
reject(function() {
});
});
});
}
I think I may have been looking at this for too long and have overlooked something fairly simple.
////**** Update ****////
Response:
HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcaWFteWFcRGVza3RvcFxOZXcgZm9sZGVyICgzKVx3ZWJhcGlcQXBpXHByb2ZpbGU=?=
X-Powered-By: ASP.NET
Date: Sun, 08 Jan 2017 00:17:26 GMT
Content-Length: 709
//* UPDATE *///
With a clean browser cache REQUEST (Fails)
POST /profile HTTP/1.1
Host: localhost:3001
Connection: keep-alive
Content-Length: 2372
Accept: application/json, text/plain, */*
Origin: http://localhost:62379
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Authorization: Bearer null
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:62379/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
I thought this may be the pre-flight but it is my understanding that would be with the OPTIONS verb not the POST verb.
The authorisation is not correctly set by the looks of it.
Authorization: Bearer null
The Response:
HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcaWFteWFcRGVza3RvcFxOZXcgZm9sZGVyICgzKVx3ZWJhcGlcQXBpXHByb2ZpbGU=?=
X-Powered-By: ASP.NET
Date: Sun, 08 Jan 2017 00:31:49 GMT
Content-Length: 709
A second Post is sent immediately after and is successful. It is actually the pre-flight.
The Request:
OPTIONS /profile HTTP/1.1
Host: localhost:3001
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:62379
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Access-Control-Request-Headers: authorization, content-type
Accept: */*
Referer: http://localhost:62379/index.html
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
And the Response:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/10.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: authorization,content-type
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcaWFteWFcRGVza3RvcFxOZXcgZm9sZGVyICgzKVx3ZWJhcGlcQXBpXHByb2ZpbGU=?=
X-Powered-By: ASP.NET
Date: Sun, 08 Jan 2017 00:34:43 GMT
Content-Length: 0
Because of this I can not get beyond the login view. The loading screen sits on error. If I refresh and login again there is no error.
The Request:
POST /profile HTTP/1.1
Host: localhost:3001
Connection: keep-alive
Content-Length: 2367
Accept: application/json, text/plain, */*
Origin: http://localhost:62379
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3ltdC5hdXRoMC5jb20vIiwic3ViIjoiZmFjZWJvb2t8MTAxNTM4MjIxOTc4MTIyNTEiLCJhdWQiOiJWWDhHMFMyUWM5cUFjYnRrM09pMVZMa2NkWGxnWlBtZSIsImV4cCI6MTQ4Mzg3MTMyNywiaWF0IjoxNDgzODM1MzI3fQ.HBQcGC6aad2pLaq3nPuhojrFT2b6Usv64p97b-DCRCU
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:62379/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
The Authorization field now has the token instead of the null value:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3ltdC5hdXRoMC5jb20vIiwic3ViIjoiZmFjZWJvb2t8MTAxNTM4MjIxOTc4MTIyNTEiLCJhdWQiOiJWWDhHMFMyUWM5cUFjYnRrM09pMVZMa2NkWGxnWlBtZSIsImV4cCI6MTQ4Mzg3MTMyNywiaWF0IjoxNDgzODM1MzI3fQ.HBQcGC6aad2pLaq3nPuhojrFT2b6Usv64p97b-DCRCU
The response is success and login proceeds.
The token seems to be injected only after a refresh.
My AUTH0 Config is:
authProvider.init({
domain: A0_DOMAIN,
clientID: A0_CLIENT,
callbackUrl: location.href,
loginState: 'out.login',
options:options
});
var refreshingToken = null;
jwtInterceptorProvider.tokenGetter = function(store, jwtHelper) {
var token = store.get('token');
var refreshToken = store.get('refreshToken');
if (token) {
if (!jwtHelper.isTokenExpired(token)) {
return store.get('token');
} else {
if (refreshingToken === null) {
refreshingToken = auth.refreshIdToken(refreshToken)
.then(function(idToken) {
store.set('token', idToken);
return idToken;
})
.finally(function() {
refreshingToken = null;
});
}
}
}
};
jwtOptionsProvider.config({
whiteListedDomains: ['localhost','https://www.ymtechno.com','https://www.ymtechno.com/_api','https://ymtechno.com/_api']
});
$httpProvider.interceptors.push('jwtInterceptor');
})
.run(function($rootScope, auth, store, jwtHelper, $location) {
var refreshingToken = null;
$rootScope.$on('$locationChangeStart',
function() {
var token = store.get('token');
var refreshToken = store.get('refreshToken');
if (token) {
if (!jwtHelper.isTokenExpired(token)) {
auth.authenticate(store.get('profile'), token);
} else {
if (refreshingToken === null) {
refreshingToken = auth.refreshIdToken(refreshToken)
.then(function(idToken) {
store.set('token', idToken);
return idToken;
})
.finally(function() {
refreshingToken = null;
});
return refreshingToken;
} else {
$location.path('login');
}
}
}
});
auth.hookEvents();
After investigating I found the interceptor was not putting the token into the auth header until the application was restarted. This was read as a CORS error because the request was not meeting the criteria for accessing the API. The token value was undefined.
A more in depth thread about injectors and headers can be found here:
Set HTTP header for one request
in the event that you come across the same issue it is a useful reference.

How to set custom headers in php unit testcases

How to send token as part of header along with the request in PHPUnit test cases.I had tried many ways but none of them are not working.
1) const TOKEN = 'XXXXXX';
public function testCreateTest()
{
$response = $this->call('POST','/test'.static::TOKEN,['code' => 'sally','sort_order'=>'test'],[],[], ['HTTP_Authorization' => 'token'],[]);
$this->assertSame(500, $response->getStatusCode());
}
2)public function testCreateTest()
{
$response = $this->call('POST','/test',[], [], [],$headers = ['token' => static::TOKEN], $cookies = [], $files = [], $server = []);
$this->assertSame(500, $response->getStatusCode());
}
When I tried to print the request the headers are not appended.The output look likes this when I run the testcases.
Cache-Control: no-cache
Content-Type: application/json
Date: Thu, 13 Oct 2016 07:38:25 GMT
Set-Cookie: XSRF-TOKEN=eyJpdiI6Ik4zdTZWbHZyXC8ybFV0MUs4R0UwNUl3PT0iLCJ2YWx1ZSI6IkFWb2cxUmtFdmljbXpxRkpcL2wwUHZyckNobVNrQYyI6IjdkY2FhMTliNjVmMDEwN2ZhNjI3ZjRmNDQxNDZmNmYyMTRkY2E4Yzg1NzY3MGY2OTEwNWY5MDA5ZmJlNDY3MDgifQ%3D%3D; expires=Thu, 13-Oct-2016 09:38:25 GMT; path=/
{"message":"Unauthorized"}
Please can anybody help me..
Thanks in advance.

How do I set request headers using Meteor HTTP?

I have a meteor method which uses HTTP.get to make a request to an API. From what I understood from the docs I can provide options with a headers object to set various things like Content-Type. I've tried this with the following code:
var r = HTTP.call("GET", apiUrl, { headers: { "Content-Type": "application/json" } });
console.log(r);
But this doesn't seem to work, the content type is till "text", see output below:
I20160302-13:50:22.706(0)? headers:
I20160302-13:50:22.706(0)? { 'access-control-allow-headers': 'Content-Type, api_key, Authorization',
I20160302-13:50:22.707(0)? 'access-control-allow-methods': 'GET',
I20160302-13:50:22.707(0)? 'access-control-allow-origin': '*',
I20160302-13:50:22.707(0)? 'content-type': 'text/plain; charset=utf-8',
I20160302-13:50:22.707(0)? date: 'Wed, 02 Mar 2016 13:50:20 GMT',
I20160302-13:50:22.707(0)? server: 'nginx/1.6.2',
I20160302-13:50:22.707(0)? 'content-length': '267',
I20160302-13:50:22.707(0)? connection: 'keep-alive' },
I've tried switching this about using "content-type" and "Content-Type". I've also tried using the shortened HTTP.get function

AngJs $http.post giving 202 in IE but working in Chrome for posting in https

AngularJs $http.post works fine with http (Non-SSL) post request
But for https requests (SSL-Enabled) it gives 202.
I have tried setting the common Accept or Content-Type headers as suiggested by many
var app = angular.module('myApp', [], function ($httpProvider) {
//$httpProvider.defaults.headers.common = { 'Accept': '*/*' };
$httpProvider.defaults.headers.post = { "Content-Type": "application/x-www-form-urlencoded" };
});
the http post are using shortcut methods
var l_url = "https://.../ABC.svc/Get";
var Data = {};
var res = $http.post(l_url, Data);
res.success(function (data, status, headers, config) {
});
res.error(function (data, status, headers, config) {
});
Below is the request headers
Key Value
Request POST /WCF/abc.svc/Get HTTP/1.1
Content-Type application/x-www-form-urlencoded
Accept application/json, text/plain, */*
Referer https://..../abc.aspx
Accept-Language en-US
Accept-Encoding gzip, deflate
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host webapps.adterminals.ae
Content-Length 2
Connection Keep-Alive
Cookie __utma=4766435.232713021.1427716113.1432028677.1437554384.8; __utmz=4766435.1427716113.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _ga=GA1.2.232713021.1427716113; ASP.NET_SessionId=mshdtgl1hy0dctzumrl1tt3q; __utmc=4766435; .ASPXAUTH=D3E9D4B2C3BA24CE4F787D90745E97D2FED3C3E601CB3AF2C4168885084D4A97396749D85C5CD59245A42FBF4F95B539F2D0AAD8F27BD0721D07BDA4FB7B4360B56077A334F3E4E409815E4189935B8A02E2D356F34B9C111EB463A0949E4B1915E6872BF7336131179E6D67C297ECED2EB13F3BC2BCB59F96FCA80C8FE794E6
Below are the response headers
Key Value
Response HTTP/1.1 202 Accepted
Server Microsoft-IIS/8.5
X-Powered-By ASP.NET
X-UA-Compatible IE=Edge
Access-Control-Allow-Origin *
Access-Control-Allow-Headers X-Requested-With,Content-Type,Accept
Access-Control-Request-Method POST,GET,PUT,DELETE,OPTIONS
Access-Control-Allow-Methods POST,GET,OPTIONS
Access-Control-Max-Age 1728000
Date Wed, 22 Jul 2015 10:02:21 GMT
Content-Length 0
Any help would be highly appreciated.

Resources