View Issue Details

IDProjectCategoryView StatusLast Update
0001624SOGo Connectorwith external serverpublic2014-01-03 00:46
ReporterStefan Assigned Toludovic  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionfixed 
Product VersionMonotone / nightly 
Summary0001624: Writing vcards with PUT does not check for changes (Danger of overwriting data)
Description

Etags should be used by sogo when communicating with CalDAV servers to ensure assist with collision avoidance of events on creation, modification and deletion.

Typical use is as follows:

PUT (Create) sends If-None-Match: *

PUT (Replace) sends If-Match: <existing etag>

DELETE sends If-Match: <existing etag>

if etag does not match server reports with statuscode 412

Additional Information

see rfc 2616 for if-match header and http://www.webdav.org/specs/rfc4918.html#rfc.section.12.1 for statuscode 412

TagsNo tags attached.

Activities

Stefan

Stefan

2012-03-07 20:00

reporter   ~0003549

Any News? This Problem is serious ...

octlabs

octlabs

2013-11-19 13:40

reporter   ~0006233

confirm to this BUG
verifyed with sogo on lates tb 17 esr and 24 with owncloud

PUT /remote.php/carddav/addressbooks/[..]/contacts/[..].vcf HTTP/1.1" 412 249

Err (Sabre_DAV_Exception_PreconditionFailed):
An If-None-Match header was specified, but the ETag matched (or * was specified).
If-None-Match

Bad solution for owncloud 5

edit
vi +1957 3rdparty/Sabre/DAV/Server.php

 if ($ifNoneMatch = $this->httpRequest->getHeader('If-None-Match')) {
        // The If-None-Match header contains an etag.
        // Only if the ETag does not match the current ETag, the request will succeed
        // The header can also contain *, in which case the request
        // will only succeed if the entity does not exist at all.
        $nodeExists = true;
        if (!$node) {
            try {
                $node = $this->tree->getNodeForPath($uri);
            } catch (Sabre_DAV_Exception_NotFound $e) {
                $nodeExists = false;
            }
        }
        if ($nodeExists) {
            $haveMatch = false;
            if ($ifNoneMatch==='*') 

{
// @XXX BAD BAD FIX
/ $haveMatch = true; /
error_log('sogo bug');
}
else ...

'If-Match' is recommended

brotherli

brotherli

2013-11-25 13:30

reporter   ~0006274

I can confirm that SOGo connector 24.0.2 also sends If-None-Match: * when updating existing contacts. That violates the RFC and causes precondition checks on the server to fail and thus the PUT command to be rejected.

evert

evert

2013-11-26 22:29

reporter   ~0006295

That's a pretty bad one.

This will basically break compatiblity with any correctly implemented CardDAV server on the planet.

I can confirm that this is an issue with every sabredav implementation, including owncloud, fruux and baikal; but I assume this breaks a lot more servers as If-None-Match: * is a simple enough feature to be implemented in the most simple servers.

jdccdevel

jdccdevel

2013-12-11 22:40

reporter   ~0006353

I'm attaching a patch which fixes this issue for me. The patch should enable the Thunderbird connector 24.0.2 to modify vcards on RFC compliant carddav servers.

I have tested with Radicale 0.8

If you are testing, I recommend you apply the patch from bug 0001411 also, and remove the stock xpi, as the patch doesn't change the version number.

jdccdevel

jdccdevel

2013-12-11 22:41

reporter  

vcard-etags.patch (3,020 bytes)   
diff -ur sogo-connector-24.0.2.jdccdevel.1/chrome/content/inverse-library/sogoWebDAV.js sogo-connector-24.0.2.jdccdevel.2/chrome/content/inverse-library/sogoWebDAV.js
--- sogo-connector-24.0.2.jdccdevel.1/chrome/content/inverse-library/sogoWebDAV.js	2013-12-11 15:27:19.635963841 -0700
+++ sogo-connector-24.0.2.jdccdevel.2/chrome/content/inverse-library/sogoWebDAV.js	2013-12-10 16:47:46.647178104 -0700
@@ -558,10 +558,29 @@
         }
         else if (operation == "PUT" || operation == "POST") {
 	    if(parameters.contentType.indexOf("text/vcard") == 0) {
-                this._sendHTTPRequest(operation,
+                if (this.cbData.data.getProperty("groupDavKey", "") == "") {
+                    dump("NOTICE: uploading new vcard with empty key\n");
+                    this._sendHTTPRequest(operation,
                                       parameters.data,
                                       { "content-type": parameters.contentType,
 				        "If-None-Match": "*" });
+                }
+                else {
+                    let oldDavVersion = this.cbData.data.getProperty("groupDavVersionPrev", "-1");
+                    dump("NOTICE: uploading modified vcard with etag: " + oldDavVersion + "\n");
+                    if (oldDavVersion != "-1") {
+                        this._sendHTTPRequest(operation,
+                                              parameters.data,
+                                              { "content-type": parameters.contentType,
+				                "If-Match": oldDavVersion });
+                    }
+                    else {
+                        dump("NOTICE: uploading modified vcard without etag\n");
+	                this._sendHTTPRequest(operation,
+                                              parameters.data,
+                                              { "content-type": parameters.contentType });
+                    }
+                }
 	    }
 	    else {
 	        this._sendHTTPRequest(operation,
diff -ur sogo-connector-24.0.2.jdccdevel.1/chrome/content/sogo-connector/addressbook/common-card-overlay.js sogo-connector-24.0.2.jdccdevel.2/chrome/content/sogo-connector/addressbook/common-card-overlay.js
--- sogo-connector-24.0.2.jdccdevel.1/chrome/content/sogo-connector/addressbook/common-card-overlay.js	2013-12-11 15:27:19.635963841 -0700
+++ sogo-connector-24.0.2.jdccdevel.2/chrome/content/sogo-connector/addressbook/common-card-overlay.js	2013-12-10 16:47:54.191178177 -0700
@@ -190,7 +190,9 @@
         if (gSCCardValues.documentDirty
             && isGroupdavDirectory(parentURI)) {
             SCSaveCategories();
+            let oldDavVersion = gEditCard.card.getProperty("groupDavVersion", "-1");
             gEditCard.card.setProperty("groupDavVersion", "-1");
+            gEditCard.card.setProperty("groupDavVersionPrev", oldDavVersion);
 
             let abManager = Components.classes["@mozilla.org/abmanager;1"]
                                       .getService(Components.interfaces.nsIAbManager);
vcard-etags.patch (3,020 bytes)   
ludovic

ludovic

2013-12-17 12:43

administrator   ~0006365

Which patch is better? 1411 or 1624?

jdccdevel

jdccdevel

2013-12-28 19:24

reporter   ~0006374

Apply them both, they fix different issues. I kept them separate so they could be vetted and applied separately by the maintainers.

ludovic

ludovic

2014-01-03 00:46

administrator   ~0006376

https://github.com/inverse-inc/sogo-connector.tb24/commit/d1b32b97890e996be48b84ab8dae15c2d8c0b9fa

Issue History

Date Modified Username Field Change
2012-02-10 10:55 Stefan New Issue
2012-03-07 20:00 Stefan Note Added: 0003549
2013-11-19 13:40 octlabs Note Added: 0006233
2013-11-25 13:30 brotherli Note Added: 0006274
2013-11-26 22:29 evert Note Added: 0006295
2013-12-11 22:40 jdccdevel Note Added: 0006353
2013-12-11 22:41 jdccdevel File Added: vcard-etags.patch
2013-12-17 12:43 ludovic Note Added: 0006365
2013-12-28 19:24 jdccdevel Note Added: 0006374
2014-01-03 00:46 ludovic Note Added: 0006376
2014-01-03 00:46 ludovic Status new => closed
2014-01-03 00:46 ludovic Assigned To => ludovic
2014-01-03 00:46 ludovic Resolution open => fixed