1# Copyright 2015 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Decorator that validates XSRF tokens."""
6
7import os
8
9from google.appengine.api import users
10from google.appengine.ext import ndb
11
12from oauth2client import xsrfutil
13
14
15class XsrfSecretKey(ndb.Model):
16  """Stores a secret XSRF key for the site."""
17  token = ndb.StringProperty(indexed=False)
18
19
20def _ValidateToken(token, user):
21  """Validates an XSRF token generated by GenerateXsrfToken."""
22  return xsrfutil.validate_token(
23      _GetSecretKey(), token, user_id=user.user_id(), action_id='')
24
25
26def GenerateToken(user):
27  return xsrfutil.generate_token(
28      _GetSecretKey(), user_id=user.user_id(), action_id='')
29
30
31def _GenerateNewSecretKey():
32  """Returns a random XSRF secret key."""
33  return str(os.urandom(16).encode('hex'))
34
35
36def _GetSecretKey():
37  """Gets or creates the secret key to use for validating XSRF tokens."""
38  key_entity = ndb.Key('XsrfSecretKey', 'site').get()
39  if not key_entity:
40    key_entity = XsrfSecretKey(id='site', token=_GenerateNewSecretKey())
41    key_entity.put()
42  return key_entity.token.encode('ascii', 'ignore')
43
44
45def TokenRequired(handler_method):
46  """A decorator to require that the XSRF token be validated for the handler."""
47
48  def CheckToken(self, *args, **kwargs):
49    user = users.get_current_user()
50    token = str(self.request.get('xsrf_token'))
51    if not user or not _ValidateToken(token, user):
52      self.abort(403)
53    handler_method(self, *args, **kwargs)
54
55  return CheckToken
56