source: main/waeup.sirp/trunk/src/waeup/sirp/authentication.txt @ 6731

Last change on this file since 6731 was 6691, checked in by Henrik Bettermann, 13 years ago

Fix test.

File size: 6.0 KB
Line 
1WAeUP portal authentication
2***************************
3
4:Test-Layer: functional
5
6We need to protect most pieces of our portals from unauthenticated
7access.
8
9Therefore users have to login to access main functionality and they
10are able to log out afterwards.
11
12Before we can check access we have to create an app:
13
14  >>> from zope.component.hooks import setSite # only needed in tests
15  >>> from waeup.sirp.app import University
16  >>> root = getRootFolder()
17  >>> u = University()
18  >>> root['app'] = u
19  >>> setSite(root['app'])                     # only needed in tests
20
21To make sure, we can 'watch' pages, we first have to initialize our
22test browser:
23
24  >>> from zope.testbrowser.testing import Browser
25  >>> browser = Browser()
26  >>> browser.handleErrors = False
27
28Creating users (principals)
29===========================
30
31Before we can login, we have to provide a user (``principal`` in Zope
32terms) with a password (and optional a title or description):
33
34  >>> root['app']['users'].addUser('bob', 'bobsecret',
35  ...                           title='Bob', description='A sample user')
36
37We can also add complete `Account` objects. An `Account` stores the
38user credentials and some metadata persistently:
39
40  >>> from waeup.sirp.authentication import Account
41  >>> alice = Account('alice', 'alicesecret')
42  >>> root['app']['users'].addAccount(alice)
43
44See ``users.txt`` for details about the UserContainer we use here.
45
46Users and local roles
47=====================
48
49Accounts also hold infos about local roles assigned to a user. In the
50beginning, users have no local roles at all:
51
52  >>> alice.getLocalRoles()
53  {}
54
55But we can tell an account, that Alice got some role for a certain
56object:
57
58  >>> chalet = object()
59  >>> root['app']['chalet'] = chalet
60  >>> alice.notifyLocalRoleChanged(chalet, 'BigBoss', granted=True)
61
62Now Alice is the Big Boss:
63
64  >>> alice.getLocalRoles()
65  {'BigBoss': [<object object at 0x...>]}
66
67When we do not want Alice to be the Big Boss we can tell that too:
68
69  >>> alice.notifyLocalRoleChanged(chalet, 'BigBoss', granted=False)
70  >>> alice.getLocalRoles()
71  {}
72
73We can also use events to trigger such actions. This is recommended
74because we do not neccessarily know where Alice lives:
75
76  >>> from waeup.sirp.users import LocalRoleSetEvent
77  >>> from zope.event import notify
78  >>> notify(LocalRoleSetEvent(chalet, 'BigBoss', 'alice',
79  ...                          granted=True))
80  >>> alice.getLocalRoles()
81  {'BigBoss': [<object object at 0x...>]}
82
83When objects are deleted, local roles are also deleted
84semi-magically. This happens through event subscribers listening to
85IObjectRemovedEvents. The latters are naturally only fired when ZODB
86stored objects are removed. Furthermore this subscriber reads the
87internal local roles table.
88
89We create a faculty and grant Bob a local role:
90
91   >>> from zope.securitypolicy.interfaces import IPrincipalRoleManager
92   >>> from waeup.sirp.university.faculty import Faculty
93   >>> faculty = Faculty()
94   >>> root['app']['bobs_fac'] = faculty
95   >>> role_manager = IPrincipalRoleManager(faculty)
96   >>> role_manager.assignRoleToPrincipal(
97   ...    'waeup.PortalManager', 'bob')
98
99We notify the machinery about that fact:
100
101   >>> notify(LocalRoleSetEvent(faculty, 'waeup.PortalManager', 'bob',
102   ...                          granted=True))
103   >>> bob = root['app']['users']['bob']
104   >>> bob.getLocalRoles()
105   {'waeup.PortalManager': [<waeup.sirp...Faculty object at 0x...>]}
106
107When we delete the faculty from ZODB, also Bobs roles are modified:
108
109   >>> del root['app']['bobs_fac']
110   >>> bob.getLocalRoles()
111   {}
112
113If one notifies the machinery of a local role removal for an object
114that cannot have local roles, this will cause no trouble:
115
116   >>> mycontext = None #object()
117   >>> notify(LocalRoleSetEvent(
118   ...   mycontext, 'waeup.PortalManager', 'bob', granted=False
119   ... )) is None
120   True
121
122When an account get deleted, also the local roles of the owner get
123removed. Let's setup a local role for `alice`:
124
125   >>> faculty = Faculty()
126   >>> root['app']['alice_fac'] = faculty
127   >>> role_manager = IPrincipalRoleManager(faculty)
128   >>> role_manager.assignRoleToPrincipal(
129   ...    'waeup.PortalManager', 'alice')
130   >>> notify(LocalRoleSetEvent(faculty, 'waeup.PortalManager', 'alice',
131   ...                          granted=True))
132
133The local role is set now:
134
135   >>> from zope.securitypolicy.interfaces import IPrincipalRoleMap
136   >>> IPrincipalRoleMap(faculty).getPrincipalsAndRoles()
137   [('waeup.PortalManager', 'alice', PermissionSetting: Allow)]
138
139But when we delete Alices account from ZODB:
140
141   >>> del root['app']['users']['alice']
142   >>> IPrincipalRoleMap(faculty).getPrincipalsAndRoles()
143   []
144
145the local role has gone.
146
147
148Logging in via side bar
149=======================
150
151We can access the front page without restrictions:
152
153  >>> browser.open('http://localhost/app')
154  >>> print browser.headers['Status']
155  200 Ok
156
157We have to go to one of the login pages first:
158
159  >>> browser.open('http://localhost/app')
160  >>> browser.getLink('Login').click()
161  >>> print browser.headers['Status']
162  200 Ok
163
164There is a login form on tis page:
165
166  >>> 'form.login' in browser.contents
167  True
168
169  >>> 'form.logout' in browser.contents
170  False
171
172We use this form:
173
174  >>> browser.getControl(name='form.login').value = 'bob'
175  >>> browser.getControl(name='form.password').value = 'invalidpw'
176  >>> browser.getControl('Login').click()
177  >>> 'You entered wrong credentials' in browser.contents
178  True
179
180  >>> browser.getControl(name='form.login').value = 'bob'
181  >>> browser.getControl(name='form.password').value = 'bobsecret'
182  >>> browser.getControl('Login').click()
183
184Now the login form is gone. Instead we have the opportunity to logout:
185
186  >>> 'form.login' in browser.contents
187  False
188
189  >>> logout = browser.getLink('Logout')
190  >>> logout
191  <Link text='Logout' url='http://localhost/app/@@logout'>
192
193The user title is also displayed in the sidebar:
194
195  >>> 'Bob' in browser.contents
196  True
197
198We can also log out afterwards:
199
200  >>> logout.click()
201  >>> print browser.contents
202  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...
203  ...Login
204  ...
205
Note: See TracBrowser for help on using the repository browser.