I'm developing a Firefox OS client for ownCloud. When I try to login and send the user credentials to the server, I need to obtain in response the cookie that I will use to authenticate in ownCloud in each request.
My problem is that as I’ve seen in Wireshark, the cookie is sent in a HTTP 302 message, but I cannot read this message in my code because Firefox handles it automatically and I read the final HTTP 200 message without cookie information in the
request.reponseText;
request.getAllResponseHeaders();
So my question is if there is any way to read this HTTP 302 message headers, or if I can obtain the cookie from Firefox OS before I send the next request, or even make Firefox OS to add the cookie automatically. I use the following code to make the POST:
request = new XMLHttpRequest({mozSystem: true});
request.open('post', serverInput, true);
request.withCredentials=true;
request.addEventListener('error', onRequestError);
request.setRequestHeader("Cookie",cookie_value);
request.setRequestHeader("Connection","keep-alive");
request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
request.send(send_string);
if(request.status == 200 || request.status==302){
response = request.responseText;
var headers = request.getAllResponseHeaders();
document.getElementById('results').innerHTML="Server found";
loginSuccessfull();
}else{
alert("Response not found");
document.getElementById('results').innerHTML="Server NOT found";
}
"mozAnon
Boolean: Setting this flag to true will cause the browser not to expose the origin and user credentials when fetching resources. Most important, this means that cookies will not be sent unless explicitly added using setRequestHeader.
mozSystem
Boolean: Setting this flag to true allows making cross-site connections without requiring the server to opt-in using CORS. Requires setting mozAnon: true, i.e. this can't be combined with sending cookies or other user credentials." [0]
I'm not sure if you're an owncloud developer, but if you are and have access to the server, you should try setting CORS headers. [1] Maybe if you can stand up a proxy server and have your app connect to the proxy server that does have CORS enabled?
There's also a withCredentials property [2] you can set on instances of xhr objects. It looks like it will add the header Access-Control-Request-Headers: "cookies" and send an HTTP OPTIONS request, which is the preflight [3]. So this would still require server side support for CORS. [4]
Though it seems like this shouldn't work based on internal comments [5], I was able to run this from a simulator and see the request and response headers:
var x = new XMLHttpRequest({ mozSystem: true });
x.open('get', 'http://stackoverflow.com');
x.onload = function () { console.log(x.getResponseHeader('Set-Cookie')); };
x.setRequestHeader('Cookie', 'hello=world;');
x.send();
You'd probably want to reassign document.cookie in the onload event, rather than logging it, if the response header exists (not every site sets cookies on every request). You'd also want to set the request header to document.cookie itself.
[0] https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#XMLHttpRequest%28%29
[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
[2] https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#Properties
[3] https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
[4] http://www.html5rocks.com/en/tutorials/cors/#toc-making-a-cors-request
[5] https://bugzilla.mozilla.org/show_bug.cgi?id=966216#c2
Related
My browser page is loaded from my server but must acquire data from another - third party.
My code to make the very first call to this third party site is:
var Vurl = "https://" + info.server + "/rest/system/session";
var Body = JSON.stringify({name: 'session', value: info.session});
var xhr = new XMLHttpRequest();
xhr.open('POST', Vurl, true);
xhr.withCredentials = true;
xhr.send(Body);
xhr.onreadystatechange = function()
{
if(this.readyState == this.HEADERS_RECEIVED)
{
// Get the raw header string
var headers = xhr.getAllResponseHeaders();
}
}
I have to place the following someplace but I don't know where. All the searches in google just state it's required but not how to implement it.
cookie('session', info.session, { sameSite: 'none', secure: true });
Can you show/tell me the proper way to set the "samesite" when working with XMLHttpRequest as shown above.
Thanks
More Info:
The call shown is sending information to the third party server. The third party reply has a "session" cookie that must replace the existing session cookie. From what I can find - chrome will not update the cookie from the third party reply unless "withCredentials" is set to true, samesite=none, and secure. My understanding is that all of that is set, then chrome will update the cookie in the browser.
My issue to resolve is that following the call, I open a websocket to the third party and it expects a "session" cookie in the header to be the same as returned from the XMLHttpRequest.
Is my understanding correct? How do I implement?
More Added - Chrome warning I'm trying to implement
A cookie associated with a cross-site resource at http://hinkle1.sipworxx.com/ was set without the SameSite attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with SameSite=None and Secure. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032
It is just a cookie:
Set-Cookie: flavor=choco; SameSite=None; Secure
In your example:
cookie('SameSite', 'None');
cookie('Secure');
Source:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
In a fetch handler triggered by a page navigation, I tried to do this:
return event.respondWith(new Response('Hello!', {
headers: {
"Set-Cookie": "TestCookie=foo; path=/; Max-Age=60;"
"TestHeader": "foo"
}
}));
Then I loaded any URL in the browser, and got the "Hello!" body. In Chrome devtools, I see the TestHeader set in the network panel. But the cookie is not showing up in the network panel, nor in the Application > Cookies viewer. document.cookie also fails to produce it.
The request is initiated by a page navigation, so there's no opportunity to set credentials: "include" on the fetch from the browser tab.
Is it possible to add a cookie to a response in the ServiceWorker? If not, is it possible to write cookies in any other way?
There's some relevant information in the Fetch specification.
As per https://fetch.spec.whatwg.org/#forbidden-response-header-name:
A forbidden response-header name is a header name that is a
byte-case-insensitive match for one of:
Set-Cookie
Set-Cookie2
And then as per item 6 in https://fetch.spec.whatwg.org/#concept-headers-append:
Otherwise, if guard is "response" and name is a forbidden response-header name, return.
This restriction on adding in the Set-Cookie header applies to either constructing new Response objects with an initial set of headers, or adding in headers after the fact to an existing Response object.
There is a plan to add in support for reading and writing cookies inside of a service worker, but that will use a mechanism other than the Set-Cookie header in a Response object. There's more information about the plans in this GitHub issue.
You may try following:
async function handleRequest(request) {
let response = await fetch(request.url, request);
// Copy the response so that we can modify headers.
response = new Response(response.body, response)
response.headers.set("Set-Cookie", "test=1234");
return response;
}
Using angular v1.3.1 i got a singular the following problem trying to implement a facade for making http request to a REST + JSON interface in the backend of the web app.
I got something like this in the code:
findSomething(value: number): ng.IPromise<api.DrugIndication[]> {
const getParams = { 'param' : 'value' };
const config:ng.IRequestShortcutConfig = {
headers: {
"Content-Type" : "application/json"
},
data: getParams
}
return this.$http.get(url,config);
}
And when the times comes to invoke it, i got an 400 Bad Request (btw: Great name for a band!) because the backend (made with Play for Scala) rejects the request inmediately. So making an inspection in the request i see that no data is being send in the body of the request/message.
So how i can send some data in the body of and HTTP Get request using angular "$http.get"?
Additional info: This doesn't happen if i the make request using the curl command from an ubuntu shell. So probably is an problem between Chrome and angular.js
If you inspect the network tab in chrome development tools you will see that this is a pre-flight OPTIONS request (Cross-Origin Resource Sharing (CORS)).
You have two ways to solve this.
Client side (this requires that your server does not require the application/json value)
GET, POST, HEAD methods only
Only browser set headers plus these
Content-Type only with:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Server side
Set something like this as a middleware on your server framework:
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization")
w.Header().Set("Access-Control-Max-Age", "86400") // firefox: max 24h, chrome 10min
return
}
For your specific framework this should work
Using config.data will send the data in the request body, use
config.params = getParams
This is from the documentation :
params – {Object.} – Map of strings or objects which will be serialized with the paramSerializer and appended as GET parameters
I am trying to make a POST request to the server (Which is a REST service)via javascript,and in my request i want to send a cookie.My below code is not working ,as I am not able to receive cookie at the server side.Below are my client side and server side code.
Client side :
var client = new XMLHttpRequest();
var request_data=JSON.stringify(data);
var endPoint="http://localhost:8080/pcap";
var cookie="session=abc";
client.open("POST", endPoint, false);//This Post will become put
client.setRequestHeader("Accept", "application/json");
client.setRequestHeader("Content-Type","application/json");
client.setRequestHeader("Set-Cookie","session=abc");
client.setRequestHeader("Cookie",cookie);
client.send(request_data);
Server Side:
public #ResponseBody ResponseEntity getPcap(HttpServletRequest request,#RequestBody PcapParameters pcap_params ){
Cookie cookies[]=request.getCookies();//Its coming as NULL
String cook=request.getHeader("Cookie");//Its coming as NULL
}
See the documentation:
Terminate these steps if header is a case-insensitive match for one of the following headers … Cookie
You cannot explicitly set a Cookie header using XHR.
It looks like you are making a cross origin request (you are using an absolute URI).
You can set withCredentials to include cookies.
True when user credentials are to be included in a cross-origin request. False when they are to be excluded in a cross-origin request and when cookies are to be ignored in its response. Initially false.
Such:
client.withCredentials = true;
This will only work if http://localhost:8080 has set a cookie using one of the supported methods (such as in an HTTP Set-Cookie response header).
Failing that, you will have to encode the data you wanted to put in the cookie somewhere else.
This can also be done with the more modern fetch
fetch(url, {
method: 'POST',
credentials: 'include'
//other options
}).then(response => console.log("Response status: ", response.status));
It seems that I am unable to change most request headers from JavaScript when making an AJAX call using XMLHttpRequest. Note that when request.setRequestHeader has to be called after request.open() in Gecko browsers (see http://ajaxpatterns.org/Talk:XMLHttpRequest_Call). When I set the Referer, it doesn't get set (I looked at the request headers sent using Firebug and Tamper Data). When I set User-Agent, it messed up the AJAX call completely. Setting Accept and Content-Type does work, however. Are we prevented from setting Referer and User-Agent in Firefox 3?
var request = new XMLHttpRequest();
var path="http://www.yahoo.com";
request.onreadystatechange=state_change;
request.open("GET", path, true);
request.setRequestHeader("Referer", "http://www.google.com");
//request.setRequestHeader("User-Agent", "Mozilla/5.0");
request.setRequestHeader("Accept","text/plain");
request.setRequestHeader("Content-Type","text/plain");
request.send(null);
function state_change()
{
if (request.readyState==4)
{// 4 = "loaded"
if (request.status==200)
{// 200 = OK
// ...our code here...
alert('ok');
}
else
{
alert("Problem retrieving XML data");
}
}
}
W3C Spec on setrequestheader.
The brief points:
If the request header had
already been set, then the new value
MUST be concatenated to the existing
value using a U+002C COMMA followed by
a U+0020 SPACE for separation.
UAs MAY give the User-Agent header an initial value, but MUST allow authors to append values to it.
However - After searching through the framework XHR in jQuery they don't allow you to change the User-Agent or Referer headers. The closest thing:
// Set header so the called script knows that it's an XMLHttpRequest
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
I'm leaning towards the opinion that what you want to do is being denied by a security policy in FF - if you want to pass some custom Referer type header you could always do:
xhr.setRequestHeader('X-Alt-Referer', 'http://www.google.com');
#gnarf answer is right . wanted to add more information .
Mozilla Bug Reference : https://bugzilla.mozilla.org/show_bug.cgi?id=627942
Terminate these steps if header is a case-insensitive match for one of the following headers:
Accept-Charset
Accept-Encoding
Access-Control-Request-Headers
Access-Control-Request-Method
Connection
Content-Length
Cookie
Cookie2
Date
DNT
Expect
Host
Keep-Alive
Origin
Referer
TE
Trailer
Transfer-Encoding
Upgrade
User-Agent
Via
Source : https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader
For people looking this up now:
It seems that now setting the User-Agent header is allowed since Firefox 43. See https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name for the current list of forbidden headers.