/
ufactory.py
240 lines (187 loc) · 7.69 KB
/
ufactory.py
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
from zope.interface import implements
from AccessControl import ClassSecurityInfo
from AccessControl.PermissionRole import _what_not_even_god_should_do
from App.class_init import InitializeClass
from App.special_dtml import DTMLFile
from Products.PluggableAuthService.PropertiedUser import PropertiedUser
from Products.PluggableAuthService.UserPropertySheet import UserPropertySheet
from Products.PluggableAuthService.interfaces.plugins import IUserFactoryPlugin
from Products.PluggableAuthService.interfaces.propertysheets \
import IPropertySheet
from Products.PluggableAuthService.interfaces.plugins import IPropertiesPlugin
from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
from Products.PlonePAS.interfaces.plugins import ILocalRolesPlugin
from Products.PlonePAS.interfaces.propertysheets import IMutablePropertySheet
try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict
manage_addPloneUserFactoryForm = DTMLFile('../zmi/PloneUserFactoryForm',
globals())
_marker = object()
def manage_addPloneUserFactory(self, id, title='', RESPONSE=None):
"""
Add a plone user factory
"""
puf = PloneUserFactory(id, title)
self._setObject(puf.getId(), puf)
if RESPONSE is not None:
return RESPONSE.redirect('manage_workspace')
class PloneUserFactory(BasePlugin):
security = ClassSecurityInfo()
meta_type = 'Plone User Factory'
implements(IUserFactoryPlugin)
def __init__(self, id, title=''):
self.id = id
self.title = title or self.meta_type
security.declarePrivate('createUser')
def createUser(self, user_id, name):
return PloneUser(user_id, name)
InitializeClass(PloneUserFactory)
class PloneUser(PropertiedUser):
security = ClassSecurityInfo()
#################################
# GRUF API
_isGroup = False
def __init__(self, id, login=None):
super(PloneUser, self).__init__(id, login)
self._propertysheets = OrderedDict()
def _getPAS(self):
# XXX This is not very optimal *at all*
return self.acl_users
def _getPlugins(self):
# XXX This is not very optimal *at all*
return self._getPAS().plugins
security.declarePublic('isGroup')
def isGroup(self):
"""Return 1 if this user is a group abstraction"""
return self._isGroup
security.declarePublic('getName')
def getName(self):
"""Get user's or group's name.
This is the id. PAS doesn't do prefixes and such like GRUF.
"""
return self.getId()
security.declarePublic('getName')
def getUserId(self):
"""Get user's or group's name.
This is the id. PAS doesn't do prefixes and such like GRUF.
"""
return self.getId()
security.declarePublic('getGroupNames')
def getGroupNames(self):
"""Return ids of this user's groups. GRUF compat."""
return self.getGroups()
security.declarePublic('getGroupIds')
getGroupIds = getGroupNames
#################################
# acquisition aware
security.declarePublic('getPropertysheet')
def getPropertysheet(self, id):
""" -> propertysheet (wrapped if supported)
"""
sheet = self._propertysheets[id]
try:
return sheet.__of__(self)
except AttributeError:
return sheet
security.declarePrivate('addPropertysheet')
def addPropertysheet(self, id, data):
""" -> add a prop sheet, given data which is either
a property sheet or a raw mapping.
"""
if IPropertySheet.providedBy(data):
sheet = data
else:
sheet = UserPropertySheet(id, **data)
if self._propertysheets.get(id) is not None:
raise KeyError('Duplicate property sheet: %s' % id)
self._propertysheets[id] = sheet
def _getPropertyPlugins(self):
return self._getPAS().plugins.listPlugins(IPropertiesPlugin)
security.declarePrivate('getOrderedPropertySheets')
def getOrderedPropertySheets(self):
return self._propertysheets.values()
#################################
# local roles plugin type delegation
def _getLocalRolesPlugins(self):
return self._getPAS().plugins.listPlugins(ILocalRolesPlugin)
def getRolesInContext(self, object):
lrmanagers = self._getLocalRolesPlugins()
roles = set([])
for lrid, lrmanager in lrmanagers:
roles.update(lrmanager.getRolesInContext(self, object))
roles.update(self.getRoles())
return list(roles)
def allowed(self, object, object_roles=None):
if object_roles is _what_not_even_god_should_do:
return 0
# Short-circuit the common case of anonymous access.
if object_roles is None or 'Anonymous' in object_roles:
return 1
# Provide short-cut access if object is protected by 'Authenticated'
# role and user is not nobody
if 'Authenticated' in object_roles and (
self.getUserName() != 'Anonymous User'):
return 1
# Check for ancient role data up front, convert if found.
# This should almost never happen, and should probably be
# deprecated at some point.
if 'Shared' in object_roles:
object_roles = self._shared_roles(object)
if object_roles is None or 'Anonymous' in object_roles:
return 1
# Check for a role match with the normal roles given to
# the user, then with local roles only if necessary. We
# want to avoid as much overhead as possible.
user_roles = self.getRoles()
for role in object_roles:
if role in user_roles:
if self._check_context(object):
return 1
return None
# check for local roles
lrmanagers = self._getLocalRolesPlugins()
for lrid, lrm in lrmanagers:
allowed = lrm.checkLocalRolesAllowed(self, object, object_roles)
# return values
# 0, 1, None
# - 1 success
# - 0 object context violation
# - None - failure
if allowed is None:
continue
return allowed
return None
def setProperties(self, properties=None, **kw):
""" Set properties on a given user.
Accepts either keyword arguments or a mapping for the ``properties``
argument. The ``properties`` argument will take precedence over
keyword arguments if both are provided; no merging will occur.
"""
if properties is None:
properties = kw
for sheet in self.getOrderedPropertySheets():
if not IMutablePropertySheet.providedBy(sheet):
continue
update = {}
for (key, value) in properties.items():
if sheet.hasProperty(key):
update[key] = value
del properties[key]
if update:
sheet.setProperties(self, update)
def getProperty(self, id, default=_marker):
for sheet in self.getOrderedPropertySheets():
if sheet.hasProperty(id):
value = sheet.getProperty(id)
if isinstance(value, unicode):
# XXX Temporarily work around the fact that
# property sheets blindly store and return
# unicode. This is sub-optimal and should be
# dealed with at the property sheets level by
# using Zope's converters.
return value.encode('utf-8')
return value
return default
InitializeClass(PloneUser)