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

Last change on this file since 6953 was 6746, checked in by uli, 13 years ago

Register main authentication.txt manually.

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