###--------------------------------------------------------------------------
### Requests.
+CONF.DEFAULTS.update(
+
+ ## A boolean switch for each operation to tell us whether it's allowed. By
+ ## default, they all are.
+ ALLOWOP = polswitch(**dict((i, True) for i in OPS)))
+
## A request object represents a single user-level operation targetted at
## multiple services. The user might be known under a different alias by
## each service, so requests operate on service/user pairs, bundled in an
class BaseRequest (object):
"""
- Base class for requests, provides basic protocol. In particular, it
- provides an empty `INFO' map, a trivial `check' method, and the obvious
- `perform' method which assumes that the `ops' list has already been
- constructed.
+ Base class for requests, provides basic protocol.
+
+ It provides an empty `INFO' map; a simple `check' method which checks the
+ operation name (in the class attribute `OP') against the configured policy
+ `CFG'ALLOWOP'; and the obvious `perform' method which assumes that the
+ `ops' list has already been constructed.
"""
+
INFO = {}
+ ## A dictionary describing the additional information returned by the
+ ## request: it maps attribute names to human-readable descriptions.
+
def check(me):
"""
Check the request to make sure we actually want to proceed.
"""
- pass
+ if not getattr(CFG.ALLOWOP, me.OP):
+ raise U.ExpectedError, \
+ (401, "Operation `%s' forbidden by policy" % me.OP)
+
def makeop(me, optype, svc, user, **kw):
"""
Hook for making operations. A policy class can substitute a
`FailOperation' to partially disallow a request.
"""
return optype(svc, user, **kw)
+
def perform(me):
"""
Perform the queued-up operations.
"""
for op in me.ops: op.perform()
return me.ops
+
CONF.export('BaseRequest', ExpectedError = U.ExpectedError)
class SetRequest (BaseRequest):
inspection. The `check' method ensures that the password is not empty, but
imposes no other policy restrictions.
"""
+
+ OP = 'set'
+
def __init__(me, accts, new):
me.new = new
me.ops = [me.makeop(SetOperation, acct.svc, acct.user, passwd = new)
for acct in accts]
+
def check(me):
if me.new == '':
raise U.ExpectedError, (400, "Empty password not permitted")
super(SetRequest, me).check()
+
CONF.export('SetRequest')
class ResetRequest (BaseRequest):
Alternatively, subclasses can override the `pwgen' method.
"""
+ OP = 'reset'
+
## Password generation parameters.
PWBYTES = 16
ENCODING = 'base32'
def pwgen(me):
return U.ENCODINGS[me.ENCODING].encode(OS.urandom(me.PWBYTES)) \
.rstrip('=')
+
CONF.export('ResetRequest')
class ClearRequest (BaseRequest):
"""
Request to clear the password for the given ACCTS.
"""
+
+ OP = 'clear'
+
def __init__(me, accts):
me.ops = [me.makeop(ClearOperation, acct.svc, acct.user)
for acct in accts]
+
CONF.export('ClearRequest')
###--------------------------------------------------------------------------