大概研究了一下 Seafile 的认证机制,包括SSO相关的认证机制,在这里主要进行一下研究成果的整合。
阶段1: 将 Seafile 发布到公网并接入 Github OAuth
为了方便对系统进行研究,我首先按照文档将Github OAuth第三方认证系统接入了自己在电脑上的Seafile系统,这个过程有些坎坷。
由于 Github 限制,接入 OAuth 的系统必须是对公网可访问的。
为了最大限度减小部署过程所产生的文件迁移,包括尽可能降低在调试过程中可能出现的与代码修改相关的问题,我决定通过 SSH 反向代理的方式,将开发机器上已经部署好的 Seafile 系统端口映射到一台现有的公网服务器上,这样即可实现公网访问,满足 Github OAuth 的要求。
首先在公网机器上,开启对应端口:
ufw allow 8000
然后在腾讯云管理端,在安全组中开放 8000 端口。
然后在客户端执行命令:
ssh [USER]@[IP] -R 8000:8000
这条命令可以将本地的 8000 端口服务放到公网电脑的 8000 端口接受服务。
但是经过上述命令部署后,访问网页,得到回复:Connection Refused。查看本机服务运行 log,发现根本没有访问请求。
为了排查是 公网 --> 公网机器8000端口 的问题,还是反向代理的问题,我在公网机器上执行了一下指令:
curl localhost:8000
能够得到正确回复,并且本机的 log 也有了 302 跳转记录。也就是说,本机的 8000 端口已经成功映射到外网机器端口,但是似乎是外网机器的 8000 端口并没有对外开放。
经过资料查找发现,默认状态下 SSH 不允许在连接过程中自定义服务端开放的端口号。必须在 /etc/ssh/sshd_config
文件中添加以下语句:
GatewayPorts clientspecified
然后运行命令:
sudo reload sshd
才能够允许客户端指定服务端的开放端口。
再次访问公网机器的 8000 端口,可以在浏览器中看到登录页面,部署成功。
之后,按照 Github OAuth 和 Seafile 所给出的文档,分别向 Github 申请 OAuth 接口,并将对应参数填入 Seafile 配置文件中,完成系统接入。
阶段2: 研究 Seafile OAuth 的认证路线
首先访问 Seafile 的单点登录界面,可以看到:地址栏的地址是 /oauth/*
,根据 urls.py
文件中的描述,找到对应的模块:
可以看到,一共有两个 URL,分别对应了登录动作和回调动作。
粗略观察发现,其中的 callback 模块主要用于获取来自 Github 的认证信息,并与本地用户建立映射。
可以看到,OAuth/views.py
的第170行,调用了 auth.authenticate()
方法:
根据以往的研究可知,authenticate()
方法将会读取填写在 settings.py
文件中的 AUTHENTICATION_BACKENDS
列表,并加载相应的类进行处理:
但是问题来了,这里只能看到一个 AuthBackend,然而进入其中的 authenticate()
方法,却发现其参数列表与我们上面调用的并不相同:
并且,这里面也并没有提到自动建立用户的逻辑,这让我感到很奇怪,经过一些研究也并没有找到问题。偶然间,我发现 Django 能够记录其认证过程所涉及到的 Backend 具体信息,于是我在调用 authenticate()
方法的地方加入了 print(user.backend)
语句,然后发现了输出:
seahub.oauth.backends.OauthRemoteUserBackend
真奇怪,明明在 settings.py
文件中只有一个 seahub.base.accounts.AuthBackend
,怎么会冒出第二个来?抱着疑问,我开启了目录搜索,将关键字设置为 OauthRemoteUserBackend
,然后,一条搜索结果愉快的出现在了我的面前:
我丢雷楼谋啊!谁家写补充代码这么写的?有毒哇。。。。
总之,找到了对应的 Backend
,自然也就能够摸清楚其建立用户的原理了:
看,先根据 username 获取到用户信息,然后判读是否存在,如果不存在就直接创建新的。同时还发现,由 OAuth 产生的用户是没有密码的:
那么这样也就催生出了第三个问题:如何完成 WebDAV 所需的认证?
阶段3: 提出 WebDAV 的解决方案
针对刚刚的问题,我们必须想出合适的认证方案,使得 WebDAV 依然能够通过内建的用户名密码输入模式来完成认证。以下是我想到的三种方案:
- 由 WebDAV 服务向 OAuth 认证服务器发送 API 请求,直接将用户名密码发送到 OAuth 认证服务器认证,不与 Seafile-Server 连接。完成认证后,再向 Seafile-Server 索要相关用户信息
- 由 Seafile-Server 服务向 OAuth 认证服务器发送 API 请求,直接从最底层改变认证模式
- 在新用户通过 OAuth 登录后,强制要求用户设置密码,从而将用户变为一个带有密码的合法普通用户