aboutsummaryrefslogtreecommitdiff
path: root/app/handlers/boot.py
diff options
context:
space:
mode:
authorMilo Casagrande <milo.casagrande@linaro.org>2014-11-20 14:43:02 +0100
committerMilo Casagrande <milo.casagrande@linaro.org>2014-11-20 14:43:49 +0100
commit90ab2227e91ef925f6fbe8adb79a5c3fbec6f6c8 (patch)
treee50ce452bec23536078c98b51e70d92edd082e92 /app/handlers/boot.py
parent0eb3e0122cc8de7537e1b4769c761381132ac242 (diff)
Add boot POST token validation.
* We validate the token to make sure it is valid. But we also need to make sure the token used can send boot reports for the provided lab. * Add some tests to cover this case. Change-Id: I5a09d8845f08cac63a43f10b533aa5804b643486
Diffstat (limited to 'app/handlers/boot.py')
-rw-r--r--app/handlers/boot.py76
1 files changed, 64 insertions, 12 deletions
diff --git a/app/handlers/boot.py b/app/handlers/boot.py
index ff9129d..01a75aa 100644
--- a/app/handlers/boot.py
+++ b/app/handlers/boot.py
@@ -21,6 +21,7 @@ import handlers.base as hbase
import handlers.common as hcommon
import handlers.response as hresponse
import models
+import models.token as mtoken
import taskqueue.tasks as taskq
import utils.db
@@ -40,29 +41,80 @@ class BootHandler(hbase.BaseHandler):
return hcommon.BOOT_VALID_KEYS.get(method, None)
def _post(self, *args, **kwargs):
- response = hresponse.HandlerResponse(202)
- if kwargs.get("reason", None):
- response.reason = (
- "Request accepted and being imported. WARNING: %s" %
- kwargs["reason"]
+ req_token = self.get_request_token()
+ lab_name = kwargs["json_obj"].get(models.LAB_NAME_KEY, None)
+
+ if self._is_valid_token(req_token, lab_name):
+ response = hresponse.HandlerResponse(202)
+ if kwargs.get("reason", None):
+ response.reason = (
+ "Request accepted and being imported. WARNING: %s" %
+ kwargs["reason"]
+ )
+ else:
+ response.reason = "Request accepted and being imported"
+ response.result = None
+
+ taskq.import_boot.apply_async(
+ [kwargs["json_obj"], kwargs["db_options"]]
)
else:
- response.reason = "Request accepted and being imported"
- response.result = None
+ response = hresponse.HandlerResponse(403)
+ response.reason = (
+ "Provided authentication token is not associated with "
+ "lab '%s'" % lab_name
+ )
+
+ return response
- taskq.import_boot.apply_async(
- [kwargs['json_obj'], kwargs['db_options']]
+ def _is_valid_token(self, req_token, lab_name):
+ """Make sure the token used to perform the POST is valid.
+
+ We are being paranoid here. We need to make sure the token used to
+ post is really associated with the provided lab name.
+
+ To be valid to post boot report, the token must either be an admin
+ token or a valid token associated with the lab.
+
+ :param req_token: The token string from the request.
+ :type req_token: str
+ :param lab_name: The name of the lab to check.
+ :type lab_name: str
+ :return True if the token is valid, False otherwise.
+ """
+ valid_lab = False
+
+ lab_doc = utils.db.find_one(
+ self.db[models.LAB_COLLECTION], [lab_name], field=models.NAME_KEY
)
- return response
+ lab_token_doc = utils.db.find_one(
+ self.db[models.TOKEN_COLLECTION], [lab_doc[models.TOKEN_KEY]]
+ )
+
+ if all([lab_doc, lab_token_doc]):
+ lab_token = mtoken.Token.from_json(lab_token_doc)
+ if all([req_token == lab_token.token, not lab_token.expired]):
+ valid_lab = True
+ elif all([lab_token.is_admin, not lab_token.expired]):
+ valid_lab = True
+ utils.LOG.warn(
+ "Received boot POST request from an admin token")
+ else:
+ utils.LOG.warn(
+ "Received token (%s) is not associated with lab '%s'",
+ req_token, lab_name
+ )
+
+ return valid_lab
def execute_delete(self, *args, **kwargs):
response = None
if self.validate_req_token("DELETE"):
- if kwargs and kwargs.get('id', None):
+ if kwargs and kwargs.get("id", None):
try:
- doc_id = kwargs['id']
+ doc_id = kwargs["id"]
obj_id = bson.objectid.ObjectId(doc_id)
if utils.db.find_one(self.collection, [obj_id]):
response = self._delete(obj_id)