Wednesday, December 19, 2012

TeamAgenda: watch out for open LDAP connections

If you are running TeamAgenda STS (version 4.x, I don't know about v5) and your server is available on public network or DMZ, make sure your LDAP port is blocked for non authorized users. Why? Because all TeamAgenda STS installations use the same user and password for LDAP!

It's cool for people who needs to connect to it to migrate away from TA (I noticed that "security problem" when I was migrating someone from TA to Kerio Connect) so that you can get the data out, but it's not cool if you have a TA server running on the whole Internet.

Tuesday, December 18, 2012

Sharing calendars with groups

I need to share calendar collections from iCal Server to groups, but sadly, with CalDAV it doesn't work. Why? Because even if the invitation is not sent by email, the user or contact that is going to get the invitation must have an email address. In Open Directory, groups don't have email addresses by default, so I said: "hey, let's add one with dscl!". So I added an existing email address to the group's OD record, but the problem is that it's the user who receive the invitation and must accept it in iCal.

So I asked the ical-server@lists.apple.com mailing list, and it seems the best ways to share calendars with groups instead of inviting every member of the group directly are:


Are you using icalserver standalone or as part of OS X server? With OS X server the wiki feature does offer a way to manage group calendars via the wiki group membership. Users who are members of a wiki can directly "subscribe" to the wiki calendar via a special sharing mode that involves simply clicking a link in the wiki calendar - that will "bind" the wiki calendar into the user's calendar home where it appears as if it were a calendar shared by an individual. 
If you don't have the wiki available, then you can do something similar with resource calendars: 
1) Create a resource for "Movie Editing". 
2) Create an OD group "movie-editing". 
3) Assign the group as a read-only or read-write proxy of the resource using the command line proxy management tool. (the command line tool is: calendarserver_manage_principals).
4) Users can "subscribe" to the shared calendar by clicking on a URL and authenticating in their browser using their calendar server credentials: 
https://calendar.example.com/calendars/resources/movieediting/calendar/?action=share
This is for servers that implements the caldav-sharing draft. To my knowledge, only iCal Server 10.7 and 10.8, or CalendarServer (the open source version of iCal Server) implements it. Other CalDAV implementations don't allow you to share individual calendar collections by iCal/Calendar.app (but some will allow you to share them by doing it by their Web interface, like Zimbra or Kerio Connect).

Wednesday, December 5, 2012

Alfresco JMX dump and authentification

I see a couple of Web pages that tell you how to do a JMX dump for Alfresco, but all of those pages, they forget to say that you have to be authentified with a admin account in Alfresco Explorer BEFORE you call the URL for the JMX dump! The JMX dump page is not asking for authentification.

So in short, you need to login at http://your.alfrescoserver.com/alfresco and after, you can do the dump at http://your.alfrescoserver.com/alfresco/faces/jsp/admin/jmx-dumper.jsp

Tuesday, November 27, 2012

Getting access to iCal Server database

On Mac OS X Server 10.7 and 10.8, the data for the iCal and Address Book services is located inside a PostgreSQL database. If you wish to see the data in the database, you can connect to the database by logging with SSH on the server, and call:
sudo psql -U _postgres caldav
All iCalendar objects are in the calendar_object table, and all vCard objects are in the addressbook_object table.

 If you wish to delete the data because you are not using the services anymore, call:
sudo dropdb -U caldav caldav

Tuesday, November 20, 2012

SSL issues with git and CentOS

Someone told me of a problem with Jenkins and Git who can't do a clone because of a SSL issue with the certificate from GitHub. I remember having the same issue a couple of months ago. The main problem is that the root certificates in CentOS (and I assume Amazon Linux and RedHat) are too old and don't have the root certificate of the provider that GitHub use.

How to fix this? See this blog post.

Sunday, October 28, 2012

MS Exchange (and Kerio) auto-discovery

In a previous post, I talked about how CalDAV clients can use auto-discovery to find the account and calendar resources (collections). In this post, I will explain how it's done for clients that supports Exchange Web Services (EWS).

The whole auto discovery process is documented on Microsoft TechNet, but I will give a summary, in a EWS context (it looks like the process for Active Directory/Outlook on Windows process in a bit different). This process applies both to MS Exchange and Kerio Connect.

As with CalDAV, the auto discovery process will take the domain from email address of the client, and it will try to make a HTTP POST to either:
  • https://autodiscover.mydomain.com/autodiscover/autodiscover.xml
  • http://autodiscover.mydomain.com/autodiscover/autodiscover.xml
For example, if your email address is probert@conatus.lan, it will try to do the POST request at https://autodiscover.conatus.lan/autodiscover/autodiscover.xml, and if it didn't get a valid response, it will try the non-secure port.

If the autodiscover.mydomain.com DNS entry is not find, the client will try to do the POST request to https://mydomain.com/autodiscover/autodiscover.xml.

The POST request that is made by the client looks like this:

<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
  <Request>
    <EMailAddress>probert@conatus.lan</EMailAddress>
 <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
  </Request>
</Autodiscover>

One important note: this POST request is authenticated by sending the user's credentials with the Authorization header. It will use either Basic or NTLM authentication.

The response will send the details of where the different services (SMTP, EWS, POP3, IMAP, etc.) are located.
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006"> 
  <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a"> 
    <User> 
      <DisplayName>Administrator</DisplayName> 
      <EMailAddress>probert@conatus.lan</EMailAddress> 
    </User> 
    <Account> 
      <AccountType>email</AccountType> 
      <Action>settings</Action> 
      <Protocol> 
        <Type>EXCH</Type> 
        <Server>myserver.conatus.lan</Server> 
        <AD>myserver.conatus.lan</AD> 
        <ASUrl>https://myserver.conatus.lan/EWS/Exchange.asmx</ASUrl> 
        <EwsUrl>https://myserver.conatus.lan/EWS/Exchange.asmx</EwsUrl> 
        <OOFUrl>https://myserver.conatus.lan/EWS/Exchange.asmx</OOFUrl> 
      </Protocol> 
      <Protocol> 
        <Type>SMTP</Type> 
        <Server>myserver.conatus.lan</Server> 
        <LoginName>probert@conatus.lan</LoginName> 
        <Port>25</Port> 
        <DomainRequired>off</DomainRequired> 
        <SPA>off</SPA> 
        <SSL>off</SSL> 
      </Protocol> 
      <Protocol> 
        <Type>SMTP</Type> 
        <Server>myserver.conatus.lan</Server> 
        <LoginName>probert@conatus.lan</LoginName> 
        <Port>465</Port> 
        <DomainRequired>off</DomainRequired> 
        <SPA>off</SPA> 
        <SSL>on</SSL> 
      </Protocol> 
      <Protocol> 
        <Type>IMAP</Type> 
        <Server>myserver.conatus.lan</Server> 
        <LoginName>probert@conatus.lan</LoginName> 
        <Port>143</Port> 
        <DomainRequired>off</DomainRequired> 
        <SPA>off</SPA> 
        <SSL>off</SSL> 
      </Protocol> 
      <Protocol> 
        <Type>IMAP</Type> 
        <Server>myserver.conatus.lan</Server> 
        <LoginName>probert@conatus.lan</LoginName> 
        <Port>993</Port> 
        <DomainRequired>off</DomainRequired> 
        <SPA>off</SPA> 
        <SSL>on</SSL> 
      </Protocol> 
      <Protocol> 
        <Type>POP3</Type> 
        <Server>myserver.conatus.lan</Server> 
        <LoginName>probert@conatus.lan</LoginName> 
        <Port>110</Port> 
        <DomainRequired>off</DomainRequired> 
        <SPA>off</SPA> 
        <SSL>off</SSL> 
      </Protocol> 
      <Protocol> 
        <Type>POP3</Type> 
        <Server>myserver.conatus.lan</Server> 
        <LoginName>probert@conatus.lan</LoginName> 
        <Port>995</Port> 
        <DomainRequired>off</DomainRequired> 
        <SPA>off</SPA> 
        <SSL>on</SSL> 
      </Protocol> 
    </Account> 
    <Action> 
      <Settings> 
        <Server> 
          <Type>MobileSync</Type> 
          <Url>https://myserver.conatus.lan/Microsoft-Server-ActiveSync/</Url> 
          <Name>https://myserver.conatus.lan/Microsoft-Server-ActiveSync/</Name>
        </Server> 
      </Settings> 
    </Action> 
  </Response> 
</Autodiscover>

Once it located the SOAP endpoint for EWS (the value of the EwsUrl attribute in the response above), the client can fetch the folders and everything else.

Sunday, October 21, 2012

Network/HTTP debugging tools

Since I'm working on CalDAV/CardDAV, Exchange Web Services and Zimbra SOAP APIs, I often need to see what's happening on the wire. To achieve this, I use a couple of tools:

  • tcpflow (installed with MacPorts). tcpflow allows use to see TCP trafic, on a specific network interface. You can use rules to specific which host(s) or port(s) that you want to sniff, which is quite useful. But since it log the packets, if the data is encrypted, you can't see unencrypted.
  • Charles Proxy. Since I really need to see the unencrypted data (my Exchange hosting provider only allow HTTPS), I'm using Charles to act as a HTTP/HTTPS proxy. Charles is really great, it will show SOAP or REST request/response in a nice layout, and the greatest thing: it can act as a HTTPS proxy, so you can see the unencrypted data! The only downside is that I wasn't able to get it to work with Outlook 2011 and a HTTPS Exchange server (it will always return a 401 Not Authorized response).
  • Debug window in Zimbra. You can use some query arguments when logging into Zimbra Web Client, arguments that will allow use to see the SOAP requests that the client is sending to the back-end. Very useful when looking for values that Zimbra is sending.
  • Debug mode in iCal. If you don't want to use a proxy, you can see what's iCal (or Calendar on 10.8) by enabling the log for HTTP activity made by iCal. To do so, just run:

    defaults write com.apple.iCal LogHTTPActivity -boolean TRUE
Update: a friend on Google+ sent me a link to a Wireshark tutorial. I must admit that I prefer tcpflow for low level debugging, but Wireshark and tcpdump are indeed other kind of tools who can use (lsof is also a tool that I used to find what applications and services are using for networking and file handles).

CrashPlan not working with Java Update 1.06.0_37

Got hit by the Java 1.7/CrashPlan problem that Java Update 1.06.0_37 creates. If you installed that update and you have Java 1.7 from Oracle on your Mac, you will need to follow this procedure.

Outlook Web Access and existing folders...

I'm working on code to create folders with Exchange Web Services (request is done by a Java API). Since I'm testing, I sometimes trash a new folder and recreate a folder with the same name as the first folder that I deleted.

But if I try to delete the new folder, Outlook Web Access (OWA) tells me that a folder with the same name already exists in the Deleted Items, so I can't delete the new folder... I have to empty the Deleted Items folder to be able to delete the folder I re-created...

Sunday, October 14, 2012

CalDAV standards and extensions

The Calendaring Standards page on CalConnect.org have a list of RFCs and drafts that CalDAV implementations uses. The main RFC is 4791, all CalDAV servers must implement this RFC.

Sadly, the page on CalConnect is missing a couple of references.


Those three extensions have been implemented in iCal Server and Calendar Server, so it's a good thing to learn them.

Update: the missing references have been added to the Calendaring Standards page.

If you wish to see which CalDAV servers is using extensions and new RFCs, I have built a (incomplete) list of CalDAV implementations and match them with the features found in the RFCs and extensions.


CalDAV handsake

When you add an CalDAV account in iCal (OS X 10.7, aka Lion, or earlier) or in Calendar (OS X 10.8, aka Mountain Lion), it does a lot of magic to configure the account. In this post, I will explain how the "handsake" is done, and what kind of data and queries is done between the client and the server. From now on, I will use iCal as the name of the client, but everything is valid for the Calendar app in 10.8 too.

When you set the account type to Automatic, as explained in my previous blog post, iCal will do a DNS query to find out what is the host name of the CalDAV server. If a SRV DNS entry have been found, iCal will get the hostname and TCP port from the SRV entry, and will do the following (here, I'm assuming that the CalDAV server found in the SRV entry is "server.macti.lan" and the TCP port is 8008):
  • Do a PROPFIND (WebDAV method) request on http://server.macti.lan:80/.well-known/caldav with the following body:
    <?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>
  • If iCal didn't get a valid response on port 80, it will try the same request, but on port 8080 instead.
  • If iCal didn't get a valid response on port 80 or 8080, it will try on the port it found in the SRV entry, in our case, port 8008.
The response from /.well-known/caldav might be a redirect (HTTP status code 301 or 302). In fact, that's what iCal Server 10.8 does, it redirect the request to http://server.macti.lan:8008/. So again, iCal will do the same request as before until it gets a 207 status code instead of a redirect. The response will look like this:

<?xml version='1.0' encoding='UTF-8'?>
<multistatus xmlns='DAV:'>
  <response>
    <href>/</href>
    <propstat>
      <prop>
        <current-user-principal>
          <href>/principals/__uids__/C0F07FAF-A20A-4A88-A518-D27E5D3074CA/</href>
        </current-user-principal>
        <resourcetype>
          <collection/>
        </resourcetype>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
</multistatus>
The value we need is the value of current-user-principal, which indicates the location of the user's "principals". With this value, iCal will make a OPTIONS request to /principals/__uids__/C0F07FAF-A20A-4A88-A518-D27E5D3074CA/. I don't know why iCal is making the request, but my guess it's doing it so that it can find which CalDAV features are supported by the CalDAV server. That list is available in the response's DAV header:
DAV: 1, access-control, calendar-access, calendar-schedule, calendar-auto-schedule, calendar-availability, inbox-availability, calendar-proxy, calendarserver-private-events, calendarserver-private-comments, calendarserver-sharing, calendarserver-sharing-no-scheduling, calendar-query-extended, calendar-default-alarms, addressbook, extended-mkcol, calendarserver-principal-property-search
This is a response from iCal Server 10.8, which supports all CalDAV features and extensions. Doing the same request to a Google Calendar server will return a lot less features/extensions.

Following the OPTIONS request, iCal will make a PROPFIND request on the same URL as the OPTIONS request, with the following body:
<?xml version="1.0" encoding="UTF-8"?>
<A:propfind xmlns:A="DAV:">
  <A:prop>
    <C:calendar-home-set xmlns:C="urn:ietf:params:xml:ns:caldav"/>
    <C:calendar-user-address-set xmlns:C="urn:ietf:params:xml:ns:caldav"/>

    <A:current-user-principal/>
    <A:displayname/>
    <B:dropbox-home-URL xmlns:B="http://calendarserver.org/ns/"/>
    <B:email-address-set xmlns:B="http://calendarserver.org/ns/"/>
    <B:notification-URL xmlns:B="http://calendarserver.org/ns/"/>
    <A:principal-collection-set/>
    <A:principal-URL/>
    <A:resource-id/>
    <C:schedule-inbox-URL xmlns:C="urn:ietf:params:xml:ns:caldav"/&gt
    <C:schedule-outbox-URL xmlns:C="urn:ietf:params:xml:ns:caldav"/>    <A:supported-report-set/>
  </A:prop>
</A:propfind>
The value that we need back from this request is the value of the calendar-home-set property. This property is the URL to calendar collections. So iCal can finally found where the calendars are, and it will do a PROPFIND request to the URL found with the value of calendar-home-set. The body of that PROPFIND request is quite large so I'm not going to past it here, but in short, that PROPFIND will find the request properties for each sub-collections in the main calendar collection. For example, if the main collection is located at:
/calendars/__uids__/0B9B4FA7-8ADC-4984-8258-D04A4939A574/
The "calendar" collection will be located at:
/calendars/__uids__/0B9B4FA7-8ADC-4984-8258-D04A4939A574/calendar/ 
And the "tasks" collection:
/calendars/__uids__/0B9B4FA7-8ADC-4984-8258-D04A4939A574/tasks
So, for each sub-collection, iCal will do the following:

  • A PROPFIND request to find the value of the checksum-versions property;
  • A PROPFIND request to find the value of the getctag and sync-token properties;
  • A PROPFIND request to find the value of the getcontenttype and getetag properties;
The third request, who fetches the content type and etag, is the one that will return a link to all iCalendar objects from the calendar collection. The response will return a <response> XML attribute for each iCalendar objects, with the following structure:
  <response>
    <href>/calendars/__uids__/C0F07FAF-A20A-4A88-A518-D27E5D3074CA/calendar/20111210T013923Z-uidGen%40mbp-pascal-robert-4.local.ics</href>
    <propstat>
      <prop>
        <getcontenttype>text/calendar;charset=utf-8</getcontenttype>
        <getetag>"9b6b2d11f86891f748ef09ab0993b75c"</getetag>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
From there, iCal will simply fetch all valid iCalendar objects and display them in the calendar window. This is done by doing a REPORT request on the calendar collection, with the calendar-multiget attribute, with the list of calendar objects that the previous PROPFIND response have returned.

<?xml version="1.0" encoding="UTF-8"?><B:calendar-multiget xmlns:B="urn:ietf:params:xml:ns:caldav">  <A:prop xmlns:A="DAV:">    <A:getetag/>    <B:calendar-data/>    <C:updated-by xmlns:C="http://calendarserver.org/ns/"/>    <C:created-by xmlns:C="http://calendarserver.org/ns/"/>  </A:prop>  <A:href xmlns:A="DAV:">/calendars/__uids__/C0F07FAF-A20A-4A88-A518-D27E5D3074CA/calendar/20111210T013923Z-uidGen%40mbp-pascal-robert-4.local.ics</A:href></B:calendar-multiget> 
This is the response:

<D:multistatus xmlns:D="DAV:">  <D:response>  <D:href>/calendars/__uids__/C0F07FAF-A20A-4A88-A518-D27E5D3074CA/calendar/20111210T013923Z-uidGen%40mbp-pascal-robert-4.local.ics</D:href>  <D:propstat>  <D:status>HTTP/1.1 200 OK</D:status>  <D:prop>  <D:getetag>"63459166486"</D:getetag>  <C:calendar-data xmlns:C="urn:ietf:params:xml:ns:caldav"> BEGIN:VCALENDAR PRODID:-//Google Inc//Google Calendar 70.9054//EN VERSION:2.0 CALSCALE:GREGORIAN X-WR-CALNAME:Pascal Robert X-WR-TIMEZONE:America/New_York  BEGIN:VEVENT DTSTART:20111209T140000Z  DTEND:20111209T180000Z DTSTAMP:20111210T021446Z  ORGANIZER;CN=probert@macti.lan:mailto:probert@macti.lan UID:20111210T021447Z-uidGen@mbp-pascal-robert-4.local  ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;CN=Pascal Robert;X-NUM-GUESTS=0:mailto:pascal.probert@gmail.com  CLASS:CONFIDENTIAL CREATED:20111210T021446Z  DESCRIPTION:Un plus long texte LAST-MODIFIED:20111210T021446Z  LOCATION:Un endroit SEQUENCE:0  STATUS:CONFIRMED SUMMARY:Événement test  TRANSP:OPAQUE BEGIN:VALARM ACTION:DISPLAY DESCRIPTION:This is an event reminder  TRIGGER:-P0DT0H30M0S END:VALARM BEGIN:VALARM ACTION:AUDIO TRIGGER;VALUE=DATE-TIME:20111209T134500Z END:VALARM END:VEVENT END:VCALENDAR </C:calendar-data>  </D:prop>  </D:propstat>  <D:propstat>  <D:status>HTTP/1.1 404 Not Found</D:status>  <D:prop>  <C:updated-by xmlns:C="http://calendarserver.org/ns/" />  <C:created-by xmlns:C="http://calendarserver.org/ns/" />  </D:prop>  </D:propstat>  </D:response> </D:multistatus>


Saturday, October 13, 2012

CalDAV/CardDAV discovery

If you use iCal/Calendar on Mac OS X or iOS, you might have seen that you don't have to specify the type of server ("Automatic" is the default type). But to work, you need to setup DNS entries so that iCal/Calendar can find the server for the user, and your CalDAV server must support "well-known" URLs. "well-known" is supported by iCal Server (OS X Server 10.7 or 10.8), Calendar Server (the open source version of iCal Server) and Kerio Connect (starting with version 7.5 I believe).

For DNS, I found how to do it in this article. In short, you need at least one SRV entry that will tell where your server is located. If your domain is "macti.lan", you need to add the following entry:
_caldavs._tcp.macti.lan.            10800 IN SRV      10 1 8443 server.macti.lan.
Where 8443 is the port on which your CalDAV server is running (8443 is the HTTPS port for iCal Server/Calendar Server, for Kerio Connect by default it's on port 443). server.macti.lan is the DNS name of the host running the CalDAV service.

You will notice that the DNS entry is _caldavs_. If your CalDAV server is running on a non-protected port, or if it's available on both ports, you should add a DNS entry like this:
_caldav._tcp.macti.lan.            10800 IN SRV      10 1 8008 server.macti.lan.
Notice that the 's' is missing in the DNS entry. If you have both entries, iCal/Calendar will try the secure entry first, and it's not working, it will try the non-secure entry after.

If you have a iCloud account with a @me.com, a SRV entry do exist:
$ dig _caldavs._tcp.me.com srv 
_caldavs._tcp.me.com. 3600 IN SRV 0 0 443 caldav.icloud.com.