Apache、LDAP 和 WSGI 编码问题

Apache, LDAP and WSGI encoding issue

我在 Ubuntu 14.04.2 (x86_64) 和 python 3.4.0 上使用 Apache 2.4.7 和 mod_wsgi 3.4。我的 python 应用程序依靠 apache 对我们公司的 LDAP 服务器 (MS Active Directory 2008) 执行用户身份验证。它还使用 OS 环境将一些额外的 LDAP 数据传递给 python 应用程序。在 apache 配置中,我像这样查询 LDAP:

…
AuthLDAPURL "ldap://server:389/DC=company,DC=lokal?sAMAccountName,sn,givenName,mail,memberOf?sub?(objectClass=*)"
AuthLDAPBindDN …
AuthLDAPBindPassword …
AuthLDAPRemoteUserAttribute sAMAccountName
AuthLDAPAuthorizePrefix AUTHENTICATE_
…

这会将一些用户数据传递到我的 WSGI 脚本,我在其中按如下方式处理信息:

# Make sure the packages from the virtualenv are found
import site
site.addsitedir('/home/user/.virtualenvs/ispot-cons/lib/python3.4/site-packages')

# Patch path for app (so that libispot can be found)
import sys
sys.path.insert(0, '/var/www/my-app/')

import os
from libispot.web import app as _application

def application(environ, start_response):
    os.environ['REMOTE_USER'] = environ.get('REMOTE_USER', "")
    os.environ['REMOTE_USER_FIRST_NAME'] = environ.get('AUTHENTICATE_GIVENNAME', "")
    os.environ['REMOTE_USER_LAST_NAME'] = environ.get('AUTHENTICATE_SN', "")
    os.environ['REMOTE_USER_EMAIL'] = environ.get('AUTHENTICATE_MAIL', "")
    os.environ['REMOTE_USER_GROUPS'] = environ.get('AUTHENTICATE_MEMBEROF', "")
    return _application(environ, start_response)

然后我可以使用 os.environ.get(…) 在我的 python 应用程序中访问此信息。 (顺便说一句:如果您有更优雅的解决方案,请告诉我!)

问题是某些用户名包含未正确编码的特殊字符(德语变音符号,例如 äöüÄÖÜ)。因此,例如,名称 Tölle 作为 Tölle.

到达我的 python 应用程序

很明显,这是一个编码问题,因为

$ echo "Tölle" | iconv --from utf-8 --to latin1 

给出了正确的 Tölle

另一个可能有帮助的观察:在我的 apache 日志中,我发现字符 ü 表示为 \xc3\x83\xc2\xbc

我在 /etc/apache2/envvars 中告诉我的 Apache 使用 LANG=de_DE.UTF-8 并且 python 3 也支持 utf-8。我似乎无法指定有关我的 LDAP 服务器的任何信息。所以我的问题是:编码在哪里混淆了,我该如何修复它?

在每个请求上将值复制到 os.environ 是不好的做法,因为如果 WSGI 服务器是 运行 多线程配置,并且并发请求相互干扰,这将失败得很惨。改为查看线程局部变量。

关于LDAP的编码数据问题,如果我理解这个问题,你需要做的是:

"Tölle".encode('latin-1').decode('utf-8')