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

Last change on this file since 6198 was 6180, checked in by uli, 13 years ago

Add local roles dicts for user accounts. That seems to
need pretty much machinery, but seems also to work. So,
why not?

We have a new event type, that should be fired when
a local role is set or unset somewhere.

We have also two new event subscribers, one listening
to the new event (and then updates the user account
local roles listings), and another one listening to
IObjectRemoved events.

The latter is the trick to keep the local role listings
in user accounts more or less up-to-date. Without it
these lists would grow and grow, not noticing that
the objects they refer to, have gone already.

We now must think about subscribing to other events.
What happens, when an object is moved or copied.
Will the local roles then be copied as well? And would
that fact be reflected in user accounts?

Beside this we have to find all places in sources
where local roles are set/unset and trigger the new
LocalRoleSetEvent? defined in users.py.

Samples for the whole new stuff are in authentication.txt.

File size: 4.6 KB
RevLine 
[4085]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
[6180]14  >>> from zope.component.hooks import setSite # only needed in tests
[4921]15  >>> from waeup.sirp.app import University
[4085]16  >>> root = getRootFolder()
17  >>> u = University()
18  >>> root['app'] = u
[6180]19  >>> setSite(root['app'])                     # only needed in tests
[4085]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
[4092]28Creating users (principals)
29===========================
[4085]30
[4092]31Before we can login, we have to provide a user (``principal`` in Zope
[4093]32terms) with a password (and optional a title or description):
[4092]33
[4744]34  >>> root['app']['users'].addUser('bob', 'bobsecret',
[4093]35  ...                           title='Bob', description='A sample user')
[4092]36
37We can also add complete `Account` objects. An `Account` stores the
38user credentials and some metadata persistently:
39
[4921]40  >>> from waeup.sirp.authentication import Account
[4092]41  >>> alice = Account('alice', 'alicesecret')
[4744]42  >>> root['app']['users'].addAccount(alice)
[4092]43
[4093]44See ``users.txt`` for details about the UserContainer we use here.
[4092]45
[6180]46Users and local roles
47=====================
[4093]48
[6180]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
[4092]113Logging in via side bar
114=======================
115
[4085]116We can access the front page without restrictions:
117
118  >>> browser.open('http://localhost/app')
119  >>> print browser.headers['Status']
120  200 Ok
121
[5404]122We have to go to one of the login pages first:
[4086]123
[5404]124  >>> browser.open('http://localhost/app/@@loginstaff')
125  >>> print browser.headers['Status']
126  200 Ok
127
128There is a login form on tis page:
129
[4086]130  >>> 'form.login' in browser.contents
131  True
132
[4093]133  >>> 'form.logout' in browser.contents
134  False
135
[4086]136We use this form:
137
[4093]138  >>> browser.getControl(name='form.login').value = 'bob'
139  >>> browser.getControl(name='form.password').value = 'bobsecret'
[4086]140  >>> browser.getControl('Login').click()
[4092]141
[4093]142Now the login form is gone. Instead we have the opportunity to logout:
143
144  >>> 'form.login' in browser.contents
145  False
146
[4617]147  >>> logout = browser.getLink('Logout')
148  >>> logout
149  <Link text='Logout' url='http://localhost/app/@@logout'>
[4093]150
[4613]151The user title is also displayed in the sidebar:
[4093]152
[4613]153  >>> 'Bob' in browser.contents
[4094]154  True
[4093]155
[4094]156We can also log out afterwards:
157
[4617]158  >>> logout.click()
[5404]159  >>> print browser.contents
160  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...
161  ...Staff Login
162  ...
[4094]163
Note: See TracBrowser for help on using the repository browser.