因为大部分策划和美术都更习惯 svn 的使用,同时因为 git 对资源文件的处理目前来说并不好1,所以我很多时候都是通过 git 主库 + svn (数据)分库的方式组织项目的,git 中记录 svn 库的当前版本号。

这样就会有一个帐号同步的问题,传统做法是使用 OpenLDAP 作为帐号管理,然后 git server 和 svnserve 把认证过程发到 OpenLDAP 处理,不过这种做法需要一个作为中心存在的管理人负责维护管理这些帐号,一般公司中就是使用这种方法的。

不过因为觉得 gogs 的账户做的挺不错的,所以这次有空的时候在想能不能把 gogs 作为认证服务后端,在经过一定时间的搜索和总结之后,发现虽然挺绕的,但是完全可行,接下来就写写在 CentOS 上怎么配置吧。

1. 安装 subversion, cyrus-sasl

1
# yum install -y subversion cyrus-sasl cyrus-sasl-plain

2. 创建 svn 库,这里作为例子我使用 /data/repo 作为版本库位置

1
# svnadmin create /data/repo

3. 修改版本库配置 svnserve.conf

配置 svnserve 使用 sasl 库进行认证,把下面的内容保存到版本库的 svnserve.conf

1
2
3
4
5
6
[general]
anon-access = none #如果需要的话,自己确定匿名用户是否可以访问
auth-access = write
authz-db = authz #如果需要的话,自己指定这个文件的位置
[sasl]
use-sasl = true #这句是关键,使用 cyrus-sasl 作为认证方式

4. 配置 sasl

配置 sasl 库使用 saslauthd 作为后端认证服务,配置如下,保存到 /etc/sasl2/svn.conf

1
2
pwcheck_method: saslauthd
mech_list: plain login

5. 配置 saslauthd

配置 saslauthd 使用 PAM 作为真正的认证服务,配置如下2,保存到 /etc/pam.d/svn

1
2
3
auth required pam_env.so
auth required pam_exec.so expose_authtok /usr/bin/gogs_auth.py
account required pam_permit.so

6. 保存 gogs_auth.py

这个脚本才是真正的认证过程实现的地方,内容如下3,保存到 /usr/bin/gogs_auth.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/env python
import httplib
import base64
import string
import sys
import os
from urlparse import urlparse
from ConfigParser import ConfigParser
DEBUG = False
ini = ConfigParser()
ini.read("/etc/gogs_auth.conf")
host = ini.get("Auth", "GOGS_HOST")
username = os.environ['PAM_USER']
password = sys.stdin.read().rstrip()
conn = None
uri = urlparse(host)
if uri.scheme == "http":
conn = httplib.HTTPConnection(uri.netloc)
else:
conn = httplib.HTTPSConnection(uri.netloc)
auth = base64.encodestring('%s:%s' % (username, password)).replace('\n', '')
headers = {
"Authorization": "Basic %s" % auth
}
conn.request('GET', '/api/v1/user/emails', None, headers)
resp = conn.getresponse()
ret = resp.status
if DEBUG:
print(host)
print(username)
print(password)
print(ret)
print(resp.read())
conn.close()
if ret == httplib.OK:
exit(0)
else:
exit(1)

7. 配置 gogs_auth.py

本来一开始是打算用环境变量来将 gogs 的地址传给脚本的,但我试了很久都没找办法,所以最后干脆给它定义一个简单的配置文件,放在 /etc/gogs_auth.conf,下面是配置格式

1
2
[Auth]
GOGS_HOST = (http|https)://gogs

GOGS_HOST 使用 http 或 https 都可以,例如下面是我自己的例子

1
2
[Auth]
GOGS_HOST = https://gogs.ifreedom.lan

8. 启动 svnserve 和 saslauthd 服务

1
2
3
4
$ systemctl enable svnserve
$ systemctl enable saslauthd
$ systemctl start svnserve
$ systemctl start saslauthd

9. 测试是否可用

saslauthd 提供了一个命令行工具testsaslauthd用于测试,在命令行中输入

1
$ testsaslauthd -s svn -u username -p password

如果输出的结果是 “OK”,则代表配置成功了。

10. 使用 Docker 封装

因为我喜欢使用 Docker 来管理这些服务,所以最后我创建了一个 Docker 容器,地址在 https://github.com/ifreedom/docker-svnserve-gogs-auth


  1. 1.git lfs 或 git annex 一类的就是为了解决这个问题才诞生的,只不过 gogs 还不支持 lfs,所以还不够通用
  2. 2.这里的最后一行 account,导致我调了很久,因为查 log 时发现 gogs_auth.py 那里的认证已经通过了,但是 svnserve 得到的回复还是拒绝,最后查看 PAM 的文档才发现不能只用 auth 模块,必须提供 account 模块才行。
  3. 3.注意一下,这里用的是 python2