Nginx将客户端证书映射到REMOTE_USER以获取uWSGI并回退到基本身份验证?

时间:2015-05-05 21:43:22

标签: ssl nginx mercurial cgi uwsgi

我正在使用Nginx和uWSGI来服务Mercurial;它通过SSL执行基本身份验证(Nginx是SSL终结器;它不会传递给Hg),但由于基本身份验证的安全性甚至超过SSL,如在包括此站点在内的各个地方所讨论的,我想允许用户也可以连接客户端证书,例如TortoiseHg支持的。

ssl_verify_client optional;
...
map $ssl_client_s_dn $ssl_client_s_dn_cn
{
    default "";
    ~/CN=(?<CN>[^/]+) $CN;
};
...
location /
{
    uwsgi_pass unix:/run/uwsgi/app/hgweb/socket;
    include uwsgi_params;
    uwsgi_param SERVER_ADDR $server_addr;
    uwsgi_param REMOTE_USER $ssl_client_s_dn_cn;
    #uwsgi_param REMOTE_USER $remote_user;
    #auth_basic "Mercurial repositories";
    #auth_basic_user_file /srv/hg/.htpasswd;

}

所以我将CN视为用户名。 但是,当没有客户端证书时,如何使其回退到基本身份验证(当证书存在时,但验证失败 - 在这种情况下只是错误)?我找到的一个例子就是让一个单独的服务器块监听另一个端口,我想避免它:https://github.com/winne27/nginx-cert-and-basic-auth/blob/master/nginx-example.conf

此外,在一些例子中,我在location中看到了以下检查;他们有必要吗? if ($ssl_client_verify != SUCCESS) { return 496; } if ($ssl_client_s_dn_cn !~ "^[a-z0-9]{1,10}$") { return 496; }鉴于http://wiki.nginx.org/IfIsEvil我认为最好避免使用if

2 个答案:

答案 0 :(得分:6)

Nginx 1.11和1.12更改了$ ssl_client_s_dn_cn的引用。

如果你来到这里并且头痛,请尝试使用此正则表达式:

map $ssl_client_s_dn $ssl_client_s_dn_cn {
        default "should_not_happen";
        ~CN=(?<CN>[^/,\"]+) $CN;
}

答案 1 :(得分:1)

我看到两种可能的解决方案,您可以覆盖uwsgi_param或使用$remote_user变量$ssl_client_s_dn_cn的默认值。

要覆盖uwsgi_param(这也应该与fastcgi_param一起使用),请按照建议使用map指令(只需删除“}”之后的“;”),然后使用指令的if_not_empty参数:

uwsgi_param REMOTE_USER $remote_user;
uwsgi_param REMOTE_USER $ssl_client_s_dn_cn if_not_empty;
如果存在,

$ssl_client_s_dn_cn应覆盖$remote_user。这种方法的优点是可以在其他地方单独使用两个不同的变量名称(例如,日志格式)。

请参阅: http://nginx.org/en/docs/http/ngx_http_uwsgi_module.html#uwsgi_param

在定义$remote_user时使用$ssl_client_s_dn_cn作为map变量的默认值:

map $ssl_client_s_dn $ssl_client_s_dn_cn
{
    default $remote_user;
    ~/CN=(?<CN>[^/]+) $CN;
}

请注意,map指令无法在server上下文中使用,而location则应该使用{{1}}。并且还要注意Nginx变量不能被覆盖。