Search code examples
ioscalendarwebdavcaldavsabredav

iOS/OS X calendar app and CalDAV service autodiscovery


I'm building my own CalDAV server using jsDAV library (a JavaScript fork of SabreDAV library). Now I'm able to serve my calendars by direct calendar url (so I've got my backends set up, both auth backend and calendar backend).

I want to be able to use automatic service discovery in iOS/OS X apps. So, if I setup a CalDAV account on my Mac or iPad I wish I just enter my server name, user name/password and not enter any urls or so.

To do so, I'm serving /.well-known/caldav address which must redirect a client to a root of my CalDAV server

So, if I've got my DAV server root placed in /dav/ I'm doing now 302 to /dav/ url from /.well-known/caldav.

Next, here is a typical iOS autodiscovery session from my server's point of view. Server accessible by HTTPS (all certs valid, no any self-signed ones), HTTP is disabled.

  1. PROPFIND /.well-known/caldav HTTP/1.1 302 39 "-" "iOS/7.1.1 (11D201) accountsd/1.0"
  2. PROPFIND /dav/ HTTP/1.1 401 - "-" "iOS/7.1.1 (11D201) accountsd/1.0"
  3. PROPFIND /dav/ HTTP/1.1" 207 - "-" "iOS/7.1.1 (11D201) accountsd/1.0"

First request is a described above service autodiscovery. All fine here, server replying with 302 to /dav/.

Second line is a first request to /dav/ without authentication headers. I reply with 'WWW-Authenticate': 'Basic realm="jsDAV" header.

Third line is a correctly authenticated DAV request (I can see it in my auth backend logs and jsDAV debug logs). Here is what I've got here:

<?xml version="1.0" encoding="UTF-8"?>
<A:propfind xmlns:A="DAV:">
    <A:prop>
        <A:current-user-principal/>
        <A:principal-URL/>
        <A:resourcetype/>
    </A:prop>
</A:propfind>

And here is what I've sending back:

<?xml version="1.0" encoding="utf-8"?>
<d:multistatus 
  xmlns:d="DAV:" 
  xmlns:a="http://ajax.org/2005/aml" 
  xmlns:cal="urn:ietf:params:xml:ns:caldav" 
  xmlns:cs="http://calendarserver.org/ns/" 
  xmlns:dav="urn:DAV">
   <d:response>
      <d:href>/dav/</d:href>
      <d:propstat>
         <d:prop>
            <d:current-user-principal>
               <d:href>/dav/principals/me/</d:href>
            </d:current-user-principal>
            <d:resourcetype>
               <d:collection/>
            </d:resourcetype>
         </d:prop>
         <d:status>HTTP/1.1 200 OK</d:status>
      </d:propstat>
    </d:response>
</d:multistatus>

After this (successfull, from my point of view) exchange iOS told me that it can't establish a secure connection to my server and offers to try insecure one.

What is wrong here? Why iOS thinks my server is broken?


Solution

  • I've found this document: http://wiki.wocommunity.org/display/~probert/CalDAV+and+CardDAV+handshake

    The answer to my question is: OPTIONS request was blocked by my frontend server. So, handshake was not fully completed.