-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathch04-auth.xml
128 lines (98 loc) · 4.98 KB
/
ch04-auth.xml
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?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>