ODK Collect Integration
Table of Contents
Note: this is just a brain dump intended to be useful for developers involved with the new XForms module - proper documentation to follow upon completion of the module.
Since version 1.1.7, ODK Collect supports HTTP BasicAuth if run via HTTPs and confronted with a proper HTTP-401 Auth challenge.
Recent Eden trunk versions implement the Auth challenge, and the best option to configure HTTPs access to Eden is to deploy it behind a web server (e.g. Apache2) with SSL.
ODK Collect Settings
Under "General Settings", configure:
- Platform: "Other"
- Configure Platform Settings
- URL: https://<your-server.domain>/eden/xforms
- Username: your username
- Password: your password
- Form list path: /formList
- Submission path: /submission
Problem: No Peer Certificate
Unfortunately, ODK Collect will refuse to work with self-signed server certificates. A certificate signed by an official CA is though too expensive for developers, so therefore here a few notes how you can get around this:
Android 4+ User-Trusted Certificates
Android 4+ allows the user to install user-trusted certificates for use via WiFi. When you download a certificate in Chrome, it will automatically invoke the certificate manager which allows you to install it as "user trusted" certificate.
But the certificate manager may report successful installation even if nothing has been installed. To understand that, you need to know two things:
(a) Android does only accept CA certificates, not server certificates
(b) Android required the certificate to be in DER format
To achieve (a):
- Create a new CA key
openssl genrsa -des3 -out rootCA.key 2048
- Create a self-signed CA root certificate
openssl req -x509 -new -nodes -key rootCA.key -days 365 -out rootCA.crt
- Create a server key (if you don't have one yet)
openssl genrsa -out host.key 2048
- Generate a CSR with the server key (if you don't have one yet)
openssl req -new -key host.key -out host.csr
- Sign the CSR with the rootCA key
openssl x509 -req -in host.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out host.crt -days 365
- Use rootCA.crt, host.key and host.crt the SSL config in your vhost (paths may differ depending on your OS):
SSLEngine On SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL SSLCertificateFile /etc/apache2/ssl.crt/host.crt SSLCertificateKeyFile /etc/apache2/ssl.key/host.key SSLCACertificateFile /etc/apache2/ssl.crt/rootCA.crt
To achieve (b):
- Convert the certificate into DER format:
openssl x509 -in rootCA.crt -outform der -out rootCA.der.crt
- Publish the rootCA.der.crt on your web server
- Open the certificate's URL in Chrome, install it as "user trusted certificate" as described above
- Verify that the certificate is installed under Settings > Security > Trusted Certificates > User
Problem: Invalid Response Status for HEAD Request
ODK Collect doesn't send the data to trigger the Auth challenge, but a HEAD request. Unfortunately, it would send the HEAD request to an interactive-format URL in Eden, so that Eden (correctly) redirects to the login page with a HTTP 303 status. This is seen as "invalid response status" by ODK Collect, so you see that error message.
There are two possible ways around this:
- Catch the "xforms" controller in AuthS3.permission.fail() - and respond with a HTTP 401 Auth challenge instead of redirecting
- Configure ODK Collect to submit to /submission.xml instead of /submission (which makes it a non-interactive URL)
Solution (1) will be implemented in future versions of the xforms module (still under development while writing this).
Problem: ODK Collect crashes when attempting to download an xform
- web2py renders whitespace before the xml processing instruction in the xform
- xform XML is not well-formed due to encoding problems (mismatching tags, restricted characters in attributes etc.)
These issues will be fixed in future versions of the xforms module (still under development while writing this).
Problem: ODK Collect crashes when attempting to submit an xform
- xform module responds to the HEAD request with a HTTP 400 status (because it doesn't contain an XForm)
Solution: catch the HEAD request in submission() and respond with a HTTP 204 status (this is what ODK Collect expects).
This solution will be implemented in future versions of the xforms module (still under development while writing this).