Client Certificates in Mongrel


#1

I’m running Apache 2.2.4 w/SSL and required client authentication
proxying to a Mongrel cluster. I can’t seem to figure out how to get
the client_certificate information out of my ruby App.

If I place <%= debug(request.env) %> into a view, the certificate
information does not seem to be included in the headers. I’ve done alot
of research on this and I’m just stumped.

Is there a directive to forward the Cert information via the proxy. I
tried to set the %{SSL_CLIENT_CERT} via the RequestHeader set directive
but that hasn’t exactly worked out for me.


#2

I think the cert is just used by Apache for the SSL handshake… it’s
not passed along as a header or anything (that would be a big header).

What I’ve done is to have Apache (in the SSL conf) add certain headers
to the request if the cert is verified:

 RequestHeader set X_FORWARDED_PROTO "https"
 RequestHeader set X_SSL_VERIFIED "true"

and then check for these headers in the rails code.

HTH.

b


#3

What I’d really like is the DN from the certificate so that I can
filter information from within the Mongrel webspace and build a
credential set from a corporate authorization webservice.

I can retrieve all the cert information from within a cgi script but
I’d like to at the very least pass the ${SSL_CLIENT_CERT_DN} via
“RequestHeader set %DN_orwhatever”- Is figuring out how to use Rewrite
RemoteUser my best option? I may just have to resign myself to that.

You’d think that with the descriptive info contained in the cert you’d
be able to use it within the app particularly if the servers you are
forwarding to are trusted(located on the same physical server therefore
sharing the same server cert etc.)

Am I fundamentally going about this the wrong way? Or does no one else
do this.

Ben M. wrote:

I think the cert is just used by Apache for the SSL handshake… it’s
not passed along as a header or anything (that would be a big header).

What I’ve done is to have Apache (in the SSL conf) add certain headers
to the request if the cert is verified:

 RequestHeader set X_FORWARDED_PROTO "https"
 RequestHeader set X_SSL_VERIFIED "true"

and then check for these headers in the rails code.

HTH.

b


#4

Well, you’re pushing the boundaries of my knowledge here… maybe try
dumping various ssl env vars[1] into the logs and see what you come up
with?

That or maybe there’s an SSL wizard lurking out there?

b

[1] http://httpd.apache.org/docs/2.2/mod/mod_ssl.html


#5

Yeah me…I finally got it to work. I think I’ve gone through enough
research, that I could write a book on how to lock down pretty much
anything at this point.

I am now able to retrieve my DistinquishedName as the
HTTP_X_FORWARDED_USER environment variable in my proxied Mongrel
instances. I wil now grab user credentials from our internal
authorization service via webservices using that info.

I removed +FakeBasicAuth from the SSLOptions list which was apparently
overriding the REMOTE_USER and performed a Rewrite with the remote_user
mentioned in previous posts and forwarded that to the request header.

Here is my setup for creating a secure mongrel environment, if it can
help anyone else save the effort that I went through:

<VirtualHost_default_:443>

<Proxy balancer://mongrel_cluster>
BalancerMember http://127.0.0.1:8000
BalancerMember http://127.0.0.1:8001
BalancerMember http://127.0.0.1:8002

#General Set-up
ServerName secure_server.chirontech.com
ServerAdmin fwkaufmATchirontechDOTcom
ErrorLog /usr/local/apache2/logs/error_log
TransferLog /usr/local/apache2/logs/access_log
CustomLog /usr/local/apache2/logs/custom_access_log combined

#Protect Proxied-Redirects
#Set an environment variable in the request header that informs
#Mongrel/Ruby that it is behind an https proxy:
RequestHeader set X_FORWARDED_PROTO ‘https’
SSLUserName SSL_CLIENT_S_DN_CN

ProxyPass / balancer://mongrel_cluster/
ProxyPassReverse / balancer://mongrelcluster/
ProxyPreserveHost On

#Rewrite the REMOTE_USER env variable into the request header
RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . -[E=RU:%1]
RequestHeader add X-FORWARDED-User %{RU}e

SSLEngine on
SSLCipherSuite
ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSL2v2:+EXP:+eNULL

#Server Certificate
SSLCertificateFile
/usr/local/apache2/conf/certs/ssl.crt/mysecure_server.crt

#Server Key
SSLCertificateKeyFile
/usr/local/apache2/conf/certs/ssl.key/mysecure_server.key

#Server Certificate Chain:
SSLCertificateChainFile /usr/local/apache2/conf/certs/ssl.crt/ca.crt

#Certificate Authority(CA)
SSLCACertificateFile /usr/local/apache2/conf/certs/ssl.crt/ca_root.crt

#Require Client Authentication via PKI
SSLVerifyClient require
SSLVerifyDepth 4

#AccessControl: currently allow only my sid through
#Will use to restrict foreign partners from entering

SSLRequire %{SSL_CLIENT_S_DN__CN}=~m/^.*(fwkaufm)

#Export environment variables and certificate data
SSLOptions +StdEnvVars +ExportCertData

#Define CustomLog
CustomLog /usr/local/apache2/logs/ssl.request_log
“%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x “%r” %b”


#6

I am working on a similar situation. I need to get the value stored
in
SSL_CLIENT_S_DN_CN . We have been doing PKI authentication for
sometime
in PHP by getting the value of $_SERVER[“SSL_CLIENT_S_DN_CN”] .

Now that I am trying some stuff in Rails I can’t seem to get anywhere.
I try to do what you do above and I get a “Bad Request” when I have
SSLUserName SSL_CLIENT_S_DN_CN in the httpd-ssl.conf file. I am able
to
get up and running when I comment it out.

Here is my config:

SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLRandomSeed connect file:/dev/urandom 512

Listen 443

AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl

SSLPassPhraseDialog builtin

SSLSessionCache “shmcb:/var/run/ssl_scache(512000)”
SSLSessionCacheTimeout 28800

SSLMutex “file:/var/run/ssl_mutex”

<VirtualHost *:443>
<Proxy balancer://mongrel_cluster>
BalancerMember http://127.0.0.1:3000

General setup for the virtual host

ServerName xxxxxxxxxxxxxx
ServerAdmin xxxxxxxxxxxxxxx
ErrorLog “/var/log/httpd-error.log”
TransferLog “/var/log/httpd-access.log”

RequestHeader set X_FORWARDED_PROTO ‘https’
SSLUserName SSL_CLIENT_S_DN_CN

ProxyPass / balancer://mongrel_cluster/
ProxyPassReverse / balancer://mongrel_cluster/
ProxyPreserveHost ON

#Rewrite the REMOTE_USER env variable into the request header
RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . -[E=RU:%1]
RequestHeader add X-FORWARDED-User %{RU}e

SSLEngine on
SSLCipherSuite
ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL

SSLCertificateFile “/usr/local/etc/apache22/ssl/xxxxxx.crt”
SSLCertificateKeyFile “/usr/local/etc/apache22/ssl/privkey.pem”
SSLCertificateChainFile “/usr/local/etc/apache22/ssl/chain.crt”

SSLCACertificatePath “/usr/local/etc/apache22/ssl.crt”
SSLVerifyClient require
SSLVerifyDepth 10

SSLOptions +StdEnvVars +ExportCertData

I pretty much cut and pasted what you had above.
And in an controller I am just doing:

<%= request.env['SSL_CLIENT_S_DN_CN'] %>

also tried

<%= request.env['HTTP-X-FORWARDED-SSL_CLIENT_S_DN_CN'] %>

All I get is blank.

Any advice would be MUCH appreciated

On Apr 24 2007, 9:17 am, Fred K. <rails-mailing-l…@andreas-