Monday, 17 May 2010

Proxy Certificates and Delegation with OPeNDAP Services

I'm back from EGU in Vienna and one topic I presented on was a solution for securing OPeNDAP services which I've developed working with colleagues at STFC and members of the development team for Earth System Grid. Services configured with the security filter middleware can accept either PKI or OpenID based authentication. So far so good but one piece that's missing and that would greatly enhance the solution would be support for delegation.

Proxy certificates would be the obvious choice since this should easily piggyback on the existing PKI based authentication adopted but alternative technologies like OAuth need more exploration. Just how easy the proxy certificate solution is explored here but first why bother? - It would give immediate compatibility with Grid based authentication schemes and would solve the delegation problem. For example in an upcoming project here a portal is required which is effectively an experimental area for scientists to gather data from different sites and combine it with their own that they upload to it. The portal could query OPeNDAP services on behalf of the user for data retrieval. In the case of a secured OPeNDAP service, the user would need to delegate authority to the portal to use their credentials to access the OPeNDAP service on their behalf.

The sequence below shows how security filter middleware intercept requests to an OPeNDAP service and redirect unauthenticated clients to an Authentication Service running over SSL.  At this point if the client submits a certificate in the SSL handshake, the service uses this to authenticate the user.  If no certificate is provided, it defaults to OpenID based sign in.

This Python snippet shows how the client code can work:
>>> import urllib2
>>> from M2Crypto import m2urllib2, SSL
>>> ctx = SSL.Context('sslv3')
>>> ctx.load_cert_chain('./proxy.pem')
>>> opener = m2urllib2.build_opener(ctx)
>>> data ='http://localhost:8001/dap/')
urllib2's redirect handler means that it will conveniently follow the HTTP redirects required in the sequence.  M2Crypto plugs into this to provide the SSL support.   The SSL context uses load_cert_chain to ensure that the complete certificate chain is loaded for the proxy certificate.  For simplicity here no peer certificate validation code has been set.

The server side filters shown in the diagram are implemented as Python WSGI middleware hosted under Apache with mod_wsgi.   The OPeNDAP service is PyDAP.   Apache provides the SSL functionality so that the Python SSLAuthentication filter has minimal work to do.   This scheme has been tested with client certificates obtained with a MyProxy CA service.  Short lived certificates obtained are issued direct from a CA hosted with MyProxy.   This presents no problems for Apache mod_ssl configuration.  Making a request with a proxy certificate however yields:
sslv3 alert certificate unknown
The OpenSSL code used by mod_ssl doesn't understand proxy certificates and key to the verification process, that it must verify a chain passed by the client of proxy certificate and the user certificate which issued the proxy certificate.   Fortunately from OpenSSL 0.9.8g there's a hack to allow support for proxy certificates, simply setting the environment variable to some value:
For Apache it means, setting this in the environment of the Apache start-up.  This NCSA howto is really helpful.  For my Ubuntu Apache configuration, there's an envvars file to which this setting can be added in /etc/apache2/.

The client verification settings are made in the configuration file:
SSLOptions +ExportCertData
SSLVerifyClient optional
SSLVerifyDepth  10
SSLCACertificatePath    /etc/grid-security/certificates/
Verification is optional so that OpenID based sign in can be invoked if no client certificate is submitted. ExportCertData enables the middleware to examine the certificate and use it to authenticate the client e.g. based on certificate Distinguished Name.

Adding proxy certificate support then has proved fairly painless for the Python/Apache server side implementation.  There's a parallel Java Tomcat implementation for ESG.  Let's hope this proves as straightforward.