~tribaal/txaws/xss-hardening

« back to all changes in this revision

Viewing changes to txaws/server/resource.py

merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
class QueryAPI(Resource):
20
20
    """Base class for  EC2-like query APIs.
21
21
 
 
22
    @param registry: The L{Registry} to use to look up L{Method}s for handling
 
23
        the API requests.
22
24
    @param path: Optionally, the actual resource path the clients are using
23
25
        when sending HTTP requests to this API, to take into account when
24
26
        validating the signature. This can differ from the one in the HTTP
29
31
 
30
32
    The following class variables must be defined by sub-classes:
31
33
 
32
 
    @ivar actions: The actions that the API supports. The 'Action' field of
33
 
        the request must contain one of these.
34
34
    @ivar signature_versions: A list of allowed values for 'SignatureVersion'.
35
35
    @cvar content_type: The content type to set the 'Content-Type' header to.
36
36
    """
48
48
        Unicode("Signature"),
49
49
        Integer("SignatureVersion", optional=True, default=2))
50
50
 
51
 
    def __init__(self, path=None):
 
51
    def __init__(self, registry=None, path=None):
52
52
        Resource.__init__(self)
53
53
        self.path = path
 
54
        self.registry = registry
 
55
 
 
56
    def get_method(self, call, *args, **kwargs):
 
57
        """Return the L{Method} instance to invoke for the given L{Call}.
 
58
 
 
59
        @param args: Positional arguments to pass to the method constructor.
 
60
        @param kwargs: Keyword arguments to pass to the method constructor.
 
61
        """
 
62
        method_class = self.registry.get(call.action, call.version)
 
63
        return method_class(*args, **kwargs)
54
64
 
55
65
    def get_principal(self, access_key):
56
66
        """Return a principal object by access key.
108
118
        """
109
119
        raise NotImplementedError("Must be implemented by subclass.")
110
120
 
 
121
    def dump_result(self, result):
 
122
        """Serialize the result of the method invokation.
 
123
 
 
124
        @param result: The L{Method} result to serialize.
 
125
        """
 
126
        return result
 
127
 
 
128
    def authorize(self, method, call):
 
129
        """Authorize to invoke the given L{Method} with the given L{Call}."""
 
130
 
111
131
    def execute(self, call):
112
132
        """Execute an API L{Call}.
113
133
 
118
138
        @raises: An L{APIError} in case the execution fails, sporting an error
119
139
            message the HTTP status code to return.
120
140
        """
121
 
        raise NotImplementedError()
 
141
        method = self.get_method(call)
 
142
        deferred = maybeDeferred(self.authorize, method, call)
 
143
        deferred.addCallback(lambda _: method.invoke(call))
 
144
        return deferred.addCallback(self.dump_result)
122
145
 
123
146
    def get_utc_time(self):
124
147
        """Return a C{datetime} object with the current time in UTC."""
142
165
        params = dict((k, v[-1]) for k, v in request.args.iteritems())
143
166
        args, rest = self.schema.extract(params)
144
167
 
145
 
        self._validate_generic_parameters(args, self.get_utc_time())
 
168
        self._validate_generic_parameters(args)
146
169
 
147
170
        def create_call(principal):
148
171
            self._validate_principal(principal, args)
157
180
        deferred.addCallback(create_call)
158
181
        return deferred
159
182
 
160
 
    def _validate_generic_parameters(self, args, utc_now):
 
183
    def _validate_generic_parameters(self, args):
161
184
        """Validate the generic request parameters.
162
185
 
163
186
        @param args: Parsed schema arguments.
164
 
        @param utc_now: The current UTC time in datetime format.
165
187
        @raises APIError: In the following cases:
166
188
            - Action is not included in C{self.actions}
167
189
            - SignatureVersion is not included in C{self.signature_versions}
169
191
            - Expires is before the current time
170
192
            - Timestamp is older than 15 minutes.
171
193
        """
172
 
        if not args.Action in self.actions:
173
 
            raise APIError(400, "InvalidAction", "The action %s is not valid "
174
 
                           "for this web service." % args.Action)
 
194
        utc_now = self.get_utc_time()
 
195
 
 
196
        if getattr(self, "actions", None) is not None:
 
197
            # Check the deprecated 'actions' attribute
 
198
            if not args.Action in self.actions:
 
199
                raise APIError(400, "InvalidAction", "The action %s is not "
 
200
                               "valid for this web service." % args.Action)
 
201
        else:
 
202
            self.registry.check(args.Action, args.Version)
175
203
 
176
204
        if not args.SignatureVersion in self.signature_versions:
177
205
            raise APIError(403, "InvalidSignature", "SignatureVersion '%s' "