2022/02/15 odoo integration webauthn

背景

最近由于业务需要, 要求在odoo中支持FIDO2的认证方式, 即在用户账户绑定FIDO2兼容的Authenticator(通常为USB key), 需要用户在正常的帐号密码登录之后, 使用USB key做二次身份确认.

调查研究

当前项目使用的odoo版本是14.0 community 版本, 而OCA 的14.0 版本的server-auth 项目并不包含FIDO2 或者U2F的认证支持, 不过在 12.0 版本 中发现有 auth_u2f 插件 实现, 所以决定从改造 12.0 版本的auth_u2f 开始, 最终目标是FIDO2odoo14 的集成

过程

整体的改造过程如下:

准备工作

由于FIDO2认证需要网站工作在TLS/HTTPS 下, 所以本地测试需要准备:

  1. 通过openssl生成网站需要的证书和私钥:certificate.pem 以及 key.pem, 方法请自行(goo)(gle) , 在nginx配置中会用到

  2. 搭建一个nginx反向代理, 关键的配置如下, 其中的 proxy_set_header X-Forwarded-HTTPS on 是解决odoo redirect 操作导致浏览器使用回HTTP请求的问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    server {
    listen 443 ssl;
    proxy_set_header X-Forwarded-Proto $scheme;
    ssl_certificate /usr/local/nginx/cert/certificate.pem; #cert
    ssl_certificate_key /usr/local/nginx/cert/key.pem; #key
    ssl_session_timeout 5m; #time out
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #supported algorithm
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #supported tls version
    ssl_prefer_server_ciphers on; #use server prefered
    ...

    location / {
    proxy_pass http://localhost:8069;
    proxy_set_header X-Forwarded-HTTPS on;
    }

    }
  3. 在odoo的系统参数中配置web.base.url 以及 web.base.url.freeze

    web.base.url -> https://localhost
    web.base.url.freeze -> True

完成之后可以测试新的https . 接下来就可以开始改造认证部分

auth_u2f -> odoo14

这部分工作主要集中在 auth_u2f 到odoo 14

  1. 下载auth_u2f插件到本地的插件目录
  2. 按照插件的说明安装依赖包 pip install python-u2flib-server
  3. 去掉方法上不支持的装饰器 @api.multi
  4. 按照标准插件安装方式安装插件

不出其他意外的话, auth_u2f 应该可以在系统中运行起来, 唯一遇到的一个问题是, 给当前用户新绑定usb key的时候, 会导致当前session出现登录失败的情况, 可能导致设备绑定出现问题, 修改方式也很简单, 修改controller ,如果发现用户已经登录, 不强制验证密钥

1
2
3
4
5
6
7
@http.route('/web/u2f/login', type='http', auth='none', sitemap=False)
def u2f_login(self, u2f_token_response=None, redirect=None, **kw):
user = request.env['res.users'].browse(request.session.uid)
if user:
return http.redirect_with_hash(self._login_redirect(
user.id, redirect=redirect))

测试后发现在 Firefox中能工作正常, 不过在chrome 中发现js错误, 由u2f-api.js 代码引起, 报extension: kmendfapggjehodndflmmgagdbamhnfd 不存在, 这个扩展应该是chrome 内置的扩展, 调查后发现应该和chrome放弃U2F支持有关 Deprecate U2F API (Cryptotoken), sighhhh! 还是Firefox耿直,所以接下来势必要转战 FIDO2

FIDO2 in odoo 14

和U2F的认证方式很类似, 包含注册部分

webauthn_reg

和认证部分

webauthn_auth

改造步骤如下:

  1. 替换对应的后端和前端U2F支持库到FIDO2的支持库, 这里选用的是 py_webauthn (server) 以及 SimpleWebAuthn (client) , 安装方式请参考对应项目文档.

  2. 后端

    1. device的模型中增加 credential (可选), credential_id , 以及 credential_pub_key 字段
    2. 在设备注册response verify通过后, 从对应的verify_registration_response 中解析出credential_idcredential_pub_key 并保存到对应的device record中
    3. 在登录时从device record中拿到creddential_id, 作为 allow_credentials 放到AuthenticationOption中
    4. 验证时从device记录中拿credential_pub_key做验证
  3. 前端的改动就比较简单, 替换auth_u2f.js 和auth_uf_frontend.js中对应的u2f-api的register 和 sign 方法为SimpleWebAuthn的startRegistration 和 startAuthentication即可

至此chrome 和 firefox都可以支持

相关网站连接

Some useful links