source: trunk/packages/invirt-base/python/invirt/authz/locker.py @ 2562

Last change on this file since 2562 was 2562, checked in by broder, 14 years ago

In invirt.authz.locker, deal with getting tokens and
authenticating/encrypting connections when necessary.

File size: 4.2 KB
Line 
1import errno
2
3from afs import acl
4from afs import fs
5from afs import pts
6
7from invirt import common
8from invirt.config import structs as config
9from invirt import remctl
10
11
12#
13# expandOwner and expandAdmin form the API that needs to be exported
14# for all authz modules.
15#
16
17
18def expandOwner(name):
19    """Expand an owner to a list of authorized users.
20
21    For the locker authz module, an owner is an Athena locker. Those
22    users who have been given the administrator ('a') bit on the root
23    of a locker are given access to any VM owned by that locker,
24    unless they also have been given a negative administrator bit.
25
26    If a locker doesn't exist, or we can't access the permissions, we
27    assume the ACL is empty.
28    """
29    try:
30        path = _lockerPath(name)
31        cell = fs.whichcell(path)
32        auth = _authenticate(cell)
33        a = acl.ACL.retrieve(path)
34
35        allowed = set()
36        for ent in a.pos:
37            if a.pos[ent] & acl.ADMINISTER:
38                allowed.update(_expandGroup(ent, cell=cell, auth=auth))
39        for ent in a.neg:
40            if a.neg[ent] & acl.ADMINISTER:
41                allowed.difference_update(_expandGroup(ent, cell=cell, auth=auth))
42
43        return allowed
44    except OSError, e:
45        if e.errno in (errno.ENOENT, errno.EACCES):
46            return []
47        else:
48            raise
49
50
51def expandAdmin(name, owner):
52    """Expand an administrator to a list of authorized users.
53
54    Because the interpretation of an administrator might depend on the
55    owner, the owner is passed in as an argument.
56
57    However, in the case of locker-based authentication, the
58    administrator is always interpreted as an AFS entry (either a user
59    or a group) in the home cell (athena.mit.edu for XVM).
60    """
61    cell = config.authz.cells[0].cell
62    auth = _authenticate(cell)
63    return _expandGroup(name, cell=cell, auth=auth)
64
65
66#
67# These are helper functions, and aren't part of the authz API
68#
69
70
71def _authenticate(cell):
72    """Acquire credentials if possible for a particular cell.
73
74    This function returns True if an authenticated connection to the
75    cell should be established; False otherwise.
76
77    If a cell isn't explicitly listed in the configuration file,
78    _authenticate will assume that it /should/ authenticate to the
79    cell.
80
81    The assumption is that choosing to authenticate to a cell will
82    fail in two cases: (a) the cell authenticates against the
83    machine's home realm and there is no PTS ID in the cell, or (b)
84    the cell doesn't authenticate against the machine's home realm and
85    doesn't have cross-realm authentication setup.
86
87    In the former case, it should be possible for the sysadmins to
88    list all cells that authenticate against the home realm (including
89    those where attempting authentication would be problematic). In
90    the latter case, such a cell would be at best distantly connected
91    to the home cell, and we probably don't want to give it quota
92    anyway.
93    """
94    for c in config.authz.cells:
95        if c.cell == cell and not c.auth:
96            return False
97
98    remctl.checkKinit()
99    common.captureOutput(['aklog', '-c', cell])
100    return True
101
102
103def _expandGroup(name, cell=None, auth=False):
104    """Expand an AFS group into a list of its members.
105
106    Because groups are not global, but can vary from cell to cell,
107    this function accepts as an optional argument the cell in which
108    this group should be resolved.
109
110    If no cell is specified, it is assumed that the default cell (or
111    ThisCell) should be used.
112
113    If the name is a user, not a group, then a single-element set with
114    the same name is returned.
115
116    As with expandOwner, if a group doesn't exist or if we're unable
117    to retrieve its membership, we assume it's empty.
118    """
119    try:
120        ent = pts.PTS(cell, 3 if auth else 0).getEntry(name)
121        if ent.id > 0:
122            return set([ent.name])
123        else:
124            return set([x.name for x in ent.members])
125    except OSError, e:
126        if e.errno in (errno.ENOENT, errno.EACCESS):
127            return set()
128        else:
129            raise
130
131
132def _lockerPath(owner):
133    """Given the name of a locker, return a path to that locker.
134
135    This turns out to be pretty simple, thanks to the /mit
136    automounter.
137    """
138    return '/mit/%s' % owner
Note: See TracBrowser for help on using the repository browser.