在Mac上的Python 3.6+中,各种与SSL相关的操作将失败(通常会出现隐藏的SSL: CERTIFICATE_VERIFY_FAILED
错误),直到您运行/Applications/Python\ 3.6/Install\ Certificates.command
来安装根证书。在遇到这样的错误之后,我用谷歌搜索,最终发现了这个解决方案(例如https://bugs.python.org/issue29065#msg283984注明),做到了,并且有效。
但是现在我想调整我的代码以捕获我之前看到的错误,并显示一条有用的错误消息,向用户解释他们需要运行/Applications/Python\ 3.6/Install\ Certificates.command
。但是,我无法轻松测试此错误处理代码,因为在运行命令后,我不再收到我想要捕获的SSL错误。
如何卸载 Install Certificates.command
安装的证书才能执行此类测试?
答案 0 :(得分:11)
.command
文件(通常)只是一个shell脚本,如果由于其扩展名在Finder中双击,则会获得特殊处理。所以,如果你想知道一个人做了什么,那就读吧。在这种情况下,它实际上是一个围绕Python脚本的裸包装器,这使得它更容易(因为你可能知道Python甚至比sh更好)。
关键部分是:
openssl_dir, openssl_cafile = os.path.split(
ssl.get_default_verify_paths().openssl_cafile)
# ...
os.symlink(relpath_to_certifi_cafile, openssl_cafile)
现在你知道它正在使用get_default_verify_paths
,很明显为什么这是相关的,以及如何检查相同的路径。默认路径为/Library/Frameworks/Python.framework/Versions/3.6/etc/openssl/cert.pem
,但这无关紧要; ssl
模块和设置工具都只使用函数来获取路径,你也可以。
要卸载,只需删除该证书:
os.remove(openssl_cafile)
...或者,也许只是重命名它,因此您可以在测试时在“已安装”和“已卸载”状态之间来回切换。
与此同时,它并非相当,因为它似乎有效地测试了这种情况,因为有四种可能性,而不仅仅是两种:
cert.pem
。cert.pem
链接到certifi
包目录中的文件,因为用户正确使用了此命令。cert.pem
没有链接到该文件,但仍然正确,因为用户手动修复了它(或者因为用户在2021年运行了程序,并且Python安装SSL CA的方式发生了变化)。cert.pem
没有链接到该文件,并且不正确,因为用户试图手动修复它但却弄错了。对于用户设置的LBYL验证,我只是检查是否存在以避免在案例3中出现窒息:
cafile = ssl.get_default_verify_paths().openssl_cafile
assert os.path.exists(cafile)
另一方面,在您收到SSL失败后,并且您希望EAFP诊断设置以帮助用户,您可以执行以下操作:
cafile = ssl.get_default_verify_paths().openssl_cafile
catarget = os.readlink(cafile)
cadir = os.path.basename(os.path.dirname(catarget))
assert cadir == 'certifi'
(无论哪种方式,你显然都想要比这更好的错误处理。)