6

this is driving me nutters.

jQuery 1.4.2, windows XP sp3

Here is my test.

Load firefox 3.5+

http://plungjan.name/test/testcors.html

works

Save the file to harddisk and run from there

From my office the external works and the internal does not

What is also interesting is that I cannot run both in one go.

Background: I do a GET to an internal web service that uses CORS. Please do NOT post any answers about FF not handling cross domain request when it does since v3.5 as detailed here and here

It works in IE8 and FF3.6.6 from one server to the other and now almost from file system (file:///) to service. Only from file system and only when FF 3.6.6 needs to negotiate (the user is already logged in, authorised and sends the credentials!) do I not get the data after negotiation. jQuery xhr returns status 0 and no data/responseText or whatever Seems to me, jQuery reacts and saves the xhr from the 401 rather than from the 200 OK later

Here is the result I get at the end of the communication when I alert the XHR object:

Status:success 
Data:[] 
XHR: 
some native functions,
readyState:4 
status:0
responseXML:null 
responseText: 
withCredentials:true

if I make a call to the same server but without needing credentials, the data is returned just fine cross domain

So the communication is as follows:

GET /restapplicationusingcors/authenticationneeded-internal/someid
Accept: application/json
Accept-Language: en
.
.
Origin: null
Cookie: LtpaToken=...

the return is

HTTP/1.1 401 Unauthorized
Server: Apache
Pragma: No-cache
Cache-Control: no-cache
Expires: Thu, 01 Jan 1970 01:00:00 CET
WWW-Authenticate: Negotiate
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html

Then FF sends

GET /restapplicationusingcors/authenticationneeded-internal/someid HTTP/1.1
Host: myhost.myintranet.bla
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6
Accept: application/json
Accept-Language: en
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: null
Cookie: LtpaToken=....
Authorization: Negotiate ....

and is rewarded with the file I need, but cannot get at in FF:

HTTP/1.1 200 OK
Date: Tue, 20 Jul 2010 12:08:39 GMT
Pragma: No-cache
Cache-Control: no-cache, max-age=600, s-maxage=3600
Expires: Thu, 01 Jan 1970 01:00:00 CET
X-Powered-By: ...
Content-Disposition: inline;filename=nnnnnn.json
Content-Language: en
Access-Control-Allow-Origin: ...
Keep-Alive: timeout=6, max=70
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8

THE DATA SENT FROM THE SERVER IS NOT IN THE XHR OBJECT

Here is my code

function getJSON(url,func,lang) {
  accept = 'application/json';
  lang=lang?lang:"*";
  // gruesome hack to handle that APPENDS the mime header to */* !!!
  // NOW HANDLED by first setting Accept to "" !!! 
//  if ($.browser.msie && url.indexOf('serveAsMime')==-1)  {
//    url+= '?serveAsMime='+accept;
//  }
  if (currentRequest != null) currentRequest.abort();
  var requestObjectJSON =   {
    url    : url,
//    dataType: "json",
    method : 'get',
    beforeSend: function(xhr){
      xhr.setRequestHeader('Accept', ""); // IE hack
      xhr.setRequestHeader('Accept', accept);
      xhr.setRequestHeader('Accept-Language', lang);
      if (url.indexOf('-internal') !=-1) {
        try {
          xhr.withCredentials = true;
          alert('set credentials') 
        }
        catch(e) {
          alert('cannot set xhr with credentials')
        }
      }
    },

    success: function(data,status,xhr) {
      var responseText = xhr.responseText;
      var responseJSON = xhr.responseJSON;


      var t = "";
      try{
        for (var o in xhr) t += '\n'+o+':'+xhr[o];
      }
      catch(e) {
        if (e.message.indexOf('.channel')==-1)alert(e.message);
      }
      alert('Status:'+status+'\nData:['+data+']\nXHR:'+t);
      func(responseText);
    },
  }
  currentRequest = $.ajax(requestObjectJSON);
}
mplungjan
  • 134,906
  • 25
  • 152
  • 209
  • "Save the file to harddisk and run from there. From my office the external works and the internal does not." I do not understand. The external/internal what works? – The Student Jul 30 '10 at 20:39
  • Retaged. You'll get some answers if you use the more popular tags.. ;) – The Student Jul 30 '10 at 20:41
  • 7
    ... and a more descriptive question title. – MatrixFrog Jul 30 '10 at 20:43
  • Have you checked any corporate firewalls and/or security software? I had an issue with jQuery/Ajax where the corporate security measures were detecting the Ajax requests and blocking them -- I wound up with similar errors to what you're getting. It's probably a longshot, as the situation is somewhat different, but it's a thought. – Nathan Loding Jul 30 '10 at 20:45
  • The title WAS more descriptive for more than a WEEK! The Tags were representative. Nathan: There are no issues at all with firewalls since the original code was running inside firewalls. – mplungjan Jul 31 '10 at 07:25
  • Please don't monkey with the tags/title like that - it'll end up getting locked. Note also that there are a number of deleted answers, it *has* had plenty of attention, but is unfortunately a very tricky question to investigate, since it is hard to repro in isolation. – Marc Gravell Jul 31 '10 at 08:42
  • I did not monkey with the tags. I changed the title to more and more descriptive until 1 day before the bounty ran out. I do not agree that this question has been answered. More investigation into whether it is an FF issue or jQuery issue is needed! Thanks – mplungjan Jul 31 '10 at 11:00
  • Have you tried to add the `file:///` or `file://localhost` to the allowed domains? Check this either: https://github.com/koto/cors-proxy-browser maybe it helps. There is no info available about the supported protocols by CORS allow headers. Not even in the recommendation. – inf3rno May 27 '14 at 13:36

4 Answers4

3

This is a stab in the dark since I don't fully understand your problem, but I think you might be having a problem with file: URLs, which are not treated as having any origin. I'm not sure it's even possible to authorize CORS from a file URL.

zwol
  • 121,956
  • 33
  • 219
  • 328
  • That is the REAL question here. But not answered. – mplungjan Jul 31 '10 at 06:26
  • I have a test here that does not work at all now with authentication :( http://talent-aid.org/test/testcors.html – mplungjan Jul 31 '10 at 07:26
  • I tried that test and I honestly can't tell if it's failing or not, and under which circumstances. I also don't understand whether this is a problem with file:, a problem with 401 responses, a problem with authentication in general, or what. You're really not explaining it well. – zwol Jul 31 '10 at 16:56
  • Sorry, I did not see this post until now. I can only truly show this on an intranet. The symptom is that it works perfectly in IE8 and in FF fails ONLY when the html is on the filesystem AND then only when the rest call needs autentication, e.g. when the server FIRST returns a 401 and when it gets the authentication from the browser and sends the data, FF or jQuery does not deliver the data to the script but still gives an OK return code... My hope was that people when they saw the headers and XHR return codes already recognised this as a bug in either FF or jQuery and knew a workaround. Thnks – mplungjan Aug 09 '10 at 14:14
  • That sounds like a bug in Firefox (or possibly jQuery, but I doubt it). Try asking this question again here: http://support.mozilla.com/en-US/questions/new – zwol Aug 09 '10 at 15:44
1

So you need to set an ajax prefilter in your model/collection in order to use CORS. Otherwise it doesn't send the cookie.

$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
    options.xhrFields = {
      withCredentials: true
    };
});

I put this in my Model/Collection initialize function.

jbrass
  • 942
  • 7
  • 23
Kirby
  • 1,882
  • 3
  • 20
  • 30
  • thanks - it is a bit moot now one year later. I appreciate the effort and hope it will help someone else. I do not have the need for the code nor the server to test it on – mplungjan Jun 07 '12 at 20:51
1

These are the conditions to be met to make CORS working with secured services:

Altogether configuration for Apache:

# Static content:
SetEnvIf      Request_URI     ".*"                            no-jk
# RESTful service:
SetEnvIf      Request_URI     "^/backend/"                    !no-jk
SetEnvIf      Request_Method  "OPTIONS"                       no-jk
# Fallback value:
SetEnv        http_origin     "*"
SetEnvIf      Origin          "^https?://(localhost|.*\.myconpany\.org)(:[0-9]+)?$" http_origin=$0

Header        set Access-Control-Allow-Credentials    "true"
Header        set Access-Control-Allow-Origin         "%{http_origin}e"
Header        set Access-Control-Allow-Methods        "GET,POST,PUT,DELETE"
Header        set Access-Control-Allow-Headers        "Content-Type, Accept"

JkMount /* loadbalancer
Community
  • 1
  • 1
dma_k
  • 9,513
  • 13
  • 68
  • 122
0

CORS with file://

If you have problems by allowing origins from the file:// protocol, according to The Web Origin Concept it should be done the same way as any other origins. I could not find information about the browser support, but I think every browser which is supporting CORS does support this one either.

The Web Origin Concept tells us the following about the file URI scheme:

   4.  If uri-scheme is "file", the implementation MAY return an
       implementation-defined value.

          NOTE: Historically, user agents have granted content from the
          file scheme a tremendous amount of privilege.  However,
          granting all local files such wide privileges can lead to
          privilege escalation attacks.  Some user agents have had
          success granting local files directory-based privileges, but
          this approach has not been widely adopted.  Other user agents
          use globally unique identifiers for each file URI, which is
          the most secure option.

According to wikipedia the domain by the file URI scheme is localhost. It is omittable by the address bar, but I don't think it is omittable in the allow origin headers. So if your browser implementation allows origin with a file URI scheme, then you should add file://localhost to your allowed origins, and everything should work properly after that.

This was how it should work, now meet reality:

  • I tested with current firefox 29.0.1, and it did not work. However the file:// protocol is transformed into null origin by this implementation. So by firefox the null works. I tried with a wider domain list, but I did not manage to allow multiple domains. It seems like firefox does not support a list with multiple domains currently.
  • I tested with chrome 35.0.1916, it works the same way as firefox did.
  • I tested with msie 11.0.9600. By request from the file protocol it always shows an allow blocked content button, even by not allowing the null origin. By other domains it works the same way as the previous browsers.

HTTP basic auth:

The credentials part I tried out with PHP and HTTP basic auth.

http://test.loc
Displays :-) when logged in and :-( when unauthorized.

<?php

function authorized()
{
    if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW']))
        return false;
    return ($_SERVER['PHP_AUTH_USER'] == 'username' && $_SERVER['PHP_AUTH_PW'] == 'password');
}

function unauthorized()
{
    header('HTTP/1.1 401 Unauthorized');
    header('WWW-Authenticate: Basic realm="Restricted Area"');
    echo '<a href="http://test.loc">:-(</a>';
}

if (!isset($_GET['logout']) && authorized()) {
    echo '<a href="http://test.loc?logout=1">:-)</a>';
} else
    unauthorized();

So this code changes the location by login and logout.

Cross domain CORS with HTTP basic auth

http://todo.loc
Gets the content of http://test.loc with cross domain XHR and displays it.

cross domain ajax<br />
<script>
    var xhr = new XMLHttpRequest();
    xhr.open('GET', "http://test.loc", true);
    xhr.withCredentials = true;
    xhr.onreadystatechange = function (){
        if (xhr.readyState==4) {
            document.body.innerHTML += xhr.responseText;
        }
    };
    xhr.send();
</script>

Requires headers by http://test.loc:

Access-Control-Allow-Origin: http://todo.loc
Access-Control-Allow-Credentials: true

Cross scheme CORS with HTTP basic auth

file:///path/x.html
Gets the content of http://test.loc with cross scheme XHR and displays it.

cross scheme ajax<br />
<script>
    var xhr = new XMLHttpRequest();
    xhr.open('GET', "http://test.loc", true);
    xhr.withCredentials = true;
    xhr.onreadystatechange = function (){
        if (xhr.readyState==4) {
            document.body.innerHTML += xhr.responseText;
        }
    };
    xhr.send();
</script>

Requires headers by http://test.loc:

Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true

Conclusion:

I tested cross-sheme CORS with credentials called from file:// and it works pretty well in firefox, chrome and msie.

inf3rno
  • 20,735
  • 9
  • 97
  • 171
  • Origin from file protocol is blank. It no longer matters It is a very old issue from FX 3.5 - we now have FX27 and have changed the way we work with this. Thanks though – mplungjan May 27 '14 at 16:03
  • Yepp, I just found that every browser uses `null` origin nowadays. – inf3rno May 27 '14 at 16:09