4 class PTRelationSet(collections.MutableSet):
5 """Collection class for the groups/members of a PTEntry.
7 This class, which acts like a set, is actually a view of the
8 groups or members associated with a PTS Entry. Changes to this
9 class are immediately reflected to the PRDB.
12 _ent: The PTEntry whose groups/members this instance
14 _set: If defined, the set of either groups or members for this
17 def __init__(self, ent):
18 """Initialize a PTRelationSet class.
21 ent: The PTEntry this instance should be associated with.
23 super(PTRelationSet, self).__init__()
28 """Load the membership/groups for this instance's PTEntry.
30 If they have not previously been loaded, this method updates
31 self._set with the set of PTEntries that are either members of
32 this group, or the groups that this entry is a member of.
34 if not hasattr(self, '_set'):
35 self._set = set(self._ent._pts.getEntry(m) for m in
36 self._ent._pts._ListMembers(self._ent.id))
39 """Add a new PTEntry to this instance's internal representation.
41 This method adds a new entry to this instance's set of
42 members/groups, but unlike PTRelationSet.add, it doesn't add
43 itself to the other instance's set.
46 elt: The element to add.
48 self._set.add(self._ent._pts.getEntry(elt))
50 def _discard(self, elt):
51 """Remove a PTEntry to this instance's internal representation.
53 This method removes an entry from this instance's set of
54 members/groups, but unlike PTRelationSet.discard, it doesn't
55 remove itself from the other instance's set.
58 elt: The element to discard.
60 self._set.discard(self._ent._pts.getEntry(elt))
63 """Count the members/groups in this set.
66 The number of entities in this instance.
72 """Iterate over members/groups in this set
75 An iterator that loops over the members/groups of this
79 return iter(self._set)
81 def __contains__(self, name):
82 """Test if a PTEntry is connected to this instance.
84 If the membership of the group hasn't already been loaded,
85 this method takes advantage of the IsAMemberOf lookup to test
88 This has the convenient advantage of working even when the
89 user doens't have permission to enumerate the group's
93 name: The element whose membership is being tested.
96 True, if name is a member of self (or if self is a member
97 of name); otherwise, False
99 name = self._ent._pts.getEntry(name)
100 if hasattr(self, '_set'):
101 return name in self._set
104 return self._ent._pts._IsAMemberOf(name.id, self._ent.id)
106 return self._ent._pts._IsAMemberOf(self._ent.id, name.id)
110 return repr(self._set)
113 """Add one new entity to a group.
115 This method will add a new user to a group, regardless of
116 whether this instance represents a group or a user. The change
117 is also immediately reflected to the PRDB.
120 TypeError: If you try to add a grop group to a group, or a
123 elt = self._ent._pts.getEntry(elt)
130 "Adding group '%s' to group '%s' is not supported." %
133 self._ent._pts._AddToGroup(elt.id, self._ent.id)
135 elt.groups._add(self._ent)
139 "Can't add user '%s' to user '%s'." %
142 self._ent._pts._AddToGroup(self._ent.id, elt.id)
144 elt.members._add(self._ent)
148 def discard(self, elt):
149 """Remove one entity from a group.
151 This method will remove a user from a group, regardless of
152 whether this instance represents a group or a user. The change
153 is also immediately reflected to the PRDB.
155 elt = self._ent._pts.getEntry(elt)
160 self._ent._pts._RemoveFromGroup(elt.id, self._ent.id)
161 elt.groups._discard(self._ent)
163 self._ent._pts._RemoveFromGroup(self._ent.id, elt.id)
164 elt.members._discard(self._ent)
169 class PTEntry(object):
170 """An entry in the AFS protection database.
172 PTEntry represents a user or group in the AFS protection
173 database. Each PTEntry is associated with a particular connection
174 to the protection database.
176 PTEntry instances should not be created directly. Instead, use the
177 "getEntry" method of the PTS object.
179 If a PTS connection is authenticated, it should be possible to
180 change most attributes on a PTEntry. These changes are immediately
181 propogated to the protection database.
184 id: The PTS ID of the entry
185 name: The username or group name of the entry
186 count: For users, the number of groups they are a member of; for
187 groups, the number of users in that group
188 flags: An integer representation of the flags set on a given
190 ngroups: The number of additional groups this entry is allowed
192 nusers: Only meaningful for foreign-cell groups, where it
193 indicates the ID of the next entry to be created from that
195 owner: A PTEntry object representing the owner of a given entry.
196 creator: A PTEntry object representing the creator of a given
197 entry. This field is read-only.
199 groups: For users, this contains a collection class representing
200 the set of groups the user is a member of.
201 users: For groups, this contains a collection class representing
202 the members of this group.
204 _attrs = ('id', 'name', 'count', 'flags', 'ngroups', 'nusers')
205 _entry_attrs = ('owner', 'creator')
207 def __new__(cls, pts, id=None, name=None):
210 raise TypeError('Must specify either a name or an id.')
212 id = pts._NameToId(name)
214 if id not in pts._cache:
216 name = pts._IdToName(id)
218 inst = super(PTEntry, cls).__new__(cls)
223 inst.members = PTRelationSet(inst)
225 inst.groups = PTRelationSet(inst)
226 pts._cache[id] = inst
227 return pts._cache[id]
231 return '<PTEntry: %s>' % self.name
233 return '<PTEntry: PTS ID %s>' % self.id
237 def _set_id(self, val):
238 del self._pts._cache[self._id]
239 self._pts._ChangeEntry(self.id, newid=val)
241 self._pts._cache[val] = self
242 id = property(_get_id, _set_id)
246 def _set_name(self, val):
247 self._pts._ChangeEntry(self.id, newname=val)
249 name = property(_get_name, _set_name)
251 def _get_krbname(self):
252 return self._pts._AfsToKrb5(self.name)
253 def _set_krbname(self, val):
254 self.name = self._pts._Krb5ToAfs(val)
255 krbname = property(_get_krbname, _set_krbname)
257 def _get_count(self):
260 count = property(_get_count)
262 def _get_flags(self):
265 def _set_flags(self, val):
266 self._pts._SetFields(self.id, access=val)
268 flags = property(_get_flags, _set_flags)
270 def _get_ngroups(self):
273 def _set_ngroups(self, val):
274 self._pts._SetFields(self.id, groups=val)
276 ngroups = property(_get_ngroups, _set_ngroups)
278 def _get_nusers(self):
281 def _set_nusers(self, val):
282 self._pts._SetFields(self.id, users=val)
284 nusers = property(_get_nusers, _set_nusers)
286 def _get_owner(self):
289 def _set_owner(self, val):
290 self._pts._ChangeEntry(self.id, newoid=self._pts.getEntry(val).id)
292 owner = property(_get_owner, _set_owner)
294 def _get_creator(self):
297 creator = property(_get_creator)
299 def _loadEntry(self):
300 if not hasattr(self, '_flags'):
301 info = self._pts._ListEntry(self._id)
302 for field in self._attrs:
303 setattr(self, '_%s' % field, getattr(info, field))
304 for field in self._entry_attrs:
305 setattr(self, '_%s' % field, self._pts.getEntry(getattr(info, field)))
308 """A connection to an AFS protection database.
310 This class represents a connection to the AFS protection database
311 for a particular cell.
313 Both the umax and gmax attributes can be changed if the connection
314 was authenticated by a principal on system:administrators for the
317 For sufficiently privileged and authenticated connections,
318 iterating over a PTS object will yield all entries in the
319 protection database, in no particular order.
322 cell: The cell to connect to. If None (the default), PTS
323 connects to the workstations home cell.
324 sec: The security level to connect with, an integer from 0 to 3:
325 - 0: unauthenticated connection
326 - 1: try authenticated, then fall back to unauthenticated
327 - 2: fail if an authenticated connection can't be established
328 - 3: same as 2, plus encrypt all traffic to the protection
332 realm: The Kerberos realm against which this cell authenticates
333 umax: The maximum user ID currently assigned (the next ID
334 assigned will be umax + 1)
335 gmax: The maximum (actually minimum) group ID currently assigned
336 (the next ID assigned will be gmax - 1, since group IDs are
339 def __init__(self, *args, **kwargs):
343 for pte in self._ListEntries():
344 yield self.getEntry(pte.id)
346 def getEntry(self, ident):
347 """Retrieve a particular PTEntry from this cell.
349 getEntry accepts either a name or PTS ID as an argument, and
350 returns a PTEntry object with that name or ID.
352 if isinstance(ident, PTEntry):
353 if ident._pts is not self:
354 raise TypeError("Entry '%s' is from a different cell." %
358 elif isinstance(ident, basestring):
359 return PTEntry(self, name=ident)
361 return PTEntry(self, id=ident)
363 def getEntryFromKrbname(self, ident):
364 """Retrieve a PTEntry matching a given Kerberos v5 principal.
366 getEntryFromKrb accepts a krb5 principal, converts it to the
367 equivalent AFS principal, and returns a PTEntry for that
369 return self.getEntry(self._Krb5ToAfs(ident))
372 """Flush the cache of PTEntry objects.
374 This method will disconnect all PTEntry objects from this PTS
375 object and flush the cache.
377 for elt in self._cache.keys():
378 del self._cache[elt]._pts
382 return self._ListMax()[0]
383 def _set_umax(self, val):
384 self._SetMaxUserId(val)
385 umax = property(_get_umax, _set_umax)
388 return self._ListMax()[1]
389 def _set_gmax(self, val):
390 self._SetMaxGroupId(val)
391 gmax = property(_get_gmax, _set_gmax)