撤消“安装Certificates.command”

时间:2018-04-18 13:14:30

标签: python macos openssl

在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安装的证书才能执行此类测试?

1 个答案:

答案 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)

...或者,也许只是重命名它,因此您可以在测试时在“已安装”和“已卸载”状态之间来回切换。

与此同时,它并非相当,因为它似乎有效地测试了这种情况,因为有四种可能性,而不仅仅是两种:

  1. cert.pem
  2. cert.pem链接到certifi包目录中的文件,因为用户正确使用了此命令。
  3. cert.pem没有链接到该文件,但仍然正确,因为用户手动修复了它(或者因为用户在2021年运行了程序,并且Python安装SSL CA的方式发生了变化)。
  4. cert.pem没有链接到该文件,并且不正确,因为用户试图手动修复它但却弄错了。
  5. 对于用户设置的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'
    

    (无论哪种方式,你显然都想要比这更好的错误处理。)