Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
128 lines (98 sloc) 4.98 KB
<?xml version="1.0" encoding="UTF-8"?>
<!--
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-->
<!-- =================================================================== -->
<sect1 id="psm.security">
<title>pySvnManager 本身的认证和授权</title>
<para>pySvnManager 作为 Subversion 授权管理的软件,如果本身没有认证和授权机制,
就会成为系统最大的漏洞。为此我们迫切需要为我们的应用增加认证和授权。还好,
这实现起来并不是很困难。</para>
<!-- ================================================================= -->
<sect2 id="psm.security.initial">
<title>为 BaseController 增加 __before__ 方法</title>
<para>__before__ 是 WSGIController 特有的方法,在 Action 执行之前执行,
可以用于初始化变量,以及做权限控制。</para>
<para>BaseController 是所有控制器的基类,在该基类增加授权功能,
会自动为其他控制器所使用。BaseController 的代码在文件 <filename>lib/base.py</filename> 中。</para>
<programlisting>
class BaseController(WSGIController):
requires_auth = []
def __before__(self, action):
if isinstance(self.requires_auth, bool) and not self.requires_auth:
pass
elif isinstance(self.requires_auth, (list, tuple)) and \
not action in self.requires_auth:
pass
else:
if 'user' not in session:
session['path_before_login'] = request.path_info
session.save()
return redirect_to(h.url_for(controller='security'))
</programlisting>
<para>从BaseController 继承的类,可以设置 requires_auth 来增加授权。
requires_auth 可以为 True 或者是一个包含要进行授权的动作列表。如果需要授权,
会检查 session 中是否包含登录信息否则跳转到登录页面(security控制器)。</para>
</sect2>
<!-- ================================================================= -->
<sect2 id="psm.security.enable">
<title>为控制器中增加授权</title>
<para>在需要增加授权的控制器中增加requires_auth的属性。</para>
<programlisting>
class CheckController(BaseController):
requires_auth = True
</programlisting>
</sect2>
<!-- ================================================================= -->
<sect2 id="psm.security.controller">
<title>Security 控制器实现</title>
<para>Security控制器用于实现用户的登录和退出。要为Security控制器增加
login 和 logout方法,并且增加登录视图模板。流程见:<xref linkend="psm.security.controller.fig1"/></para>
<sidebar>
<figure id="psm.security.controller.fig1">
<title>控制器check的MVC框架示意图</title>
<graphic fileref="images/security_controller.png"/>
</figure>
</sidebar>
<para>具体实现参见代码。</para>
</sect2>
<!-- ================================================================= -->
<sect2 id="psm.security.authz">
<title>pySvnManager 授权</title>
<para>在 SvnAuthz 类的实现中,在 svnauthz 文件中为版本库增加了管理员设置,
来进行管理员的身份验证。我们就利用同样的代码对 pySvnManager 进行授权验证。</para>
<para>具体实现参见代码。</para>
</sect2>
<!-- ================================================================= -->
<sect2 id="psm.security.unittest">
<title>添加认证后的单元测试</title>
<para>添加授权后,执行nosetests,会发现控制器的单元测试报错。
因为没有经过授权所有页面的输出都是“尚未授权”。实际上,
只要在每一个测试用例运行之前,访问 security控制器的login方法,
以实现登录,设置正确的session,则后续访问会自动带上cookie,
得到正确的授权页面。</para>
<para>在控制器的测试用例基类TestController中加上login方法,以简化登录调用:</para>
<programlisting><![CDATA[
class TestController(TestCase):
...
def login(self, username, password=""):
res = self.app.get(url_for(controller='security'))
form = res.forms[0]
form['username'] = username
if not password:
d = eval(config.get('test_users', {}))
password = d.get(username,'')
form['password'] = password
form.submit()
]]></programlisting>
<para>在测试用例中调用login方法:</para>
<programlisting><![CDATA[
self.login('root')
res = self.app.get(url_for(controller='check'))
assert res.status == 200
assert '''<input type="submit" name="submit" value='Check Permissions'>''' in res.body
assert res.c.reposlist == ['/', u'repos1', u'repos2', u'repos3', u'document']
]]></programlisting>
</sect2>
</sect1>