1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Helper methods for creating & verifying XSRF tokens."""
17
18 __authors__ = [
19 '"Doug Coker" <dcoker@google.com>',
20 '"Joe Gregorio" <jcgregorio@google.com>',
21 ]
22
23
24 import base64
25 import hmac
26 import time
27
28 import six
29 from oauth2client import util
30
31
32
33 DELIMITER = b':'
34
35
36
37 DEFAULT_TIMEOUT_SECS = 1*60*60
41 if isinstance(s, bytes):
42 return s
43 s = str(s)
44 if isinstance(s, six.text_type):
45 return s.encode('utf-8')
46 return s
47
51 """Generates a URL-safe token for the given user, action, time tuple.
52
53 Args:
54 key: secret key to use.
55 user_id: the user ID of the authenticated user.
56 action_id: a string identifier of the action they requested
57 authorization for.
58 when: the time in seconds since the epoch at which the user was
59 authorized for this action. If not set the current time is used.
60
61 Returns:
62 A string XSRF protection token.
63 """
64 when = _force_bytes(when or int(time.time()))
65 digester = hmac.new(_force_bytes(key))
66 digester.update(_force_bytes(user_id))
67 digester.update(DELIMITER)
68 digester.update(_force_bytes(action_id))
69 digester.update(DELIMITER)
70 digester.update(when)
71 digest = digester.digest()
72
73 token = base64.urlsafe_b64encode(digest + DELIMITER + when)
74 return token
75
79 """Validates that the given token authorizes the user for the action.
80
81 Tokens are invalid if the time of issue is too old or if the token
82 does not match what generateToken outputs (i.e. the token was forged).
83
84 Args:
85 key: secret key to use.
86 token: a string of the token generated by generateToken.
87 user_id: the user ID of the authenticated user.
88 action_id: a string identifier of the action they requested
89 authorization for.
90
91 Returns:
92 A boolean - True if the user is authorized for the action, False
93 otherwise.
94 """
95 if not token:
96 return False
97 try:
98 decoded = base64.urlsafe_b64decode(token)
99 token_time = int(decoded.split(DELIMITER)[-1])
100 except (TypeError, ValueError):
101 return False
102 if current_time is None:
103 current_time = time.time()
104
105 if current_time - token_time > DEFAULT_TIMEOUT_SECS:
106 return False
107
108
109 expected_token = generate_token(key, user_id, action_id=action_id,
110 when=token_time)
111 if len(token) != len(expected_token):
112 return False
113
114
115 different = 0
116 for x, y in zip(bytearray(token), bytearray(expected_token)):
117 different |= x ^ y
118 return not different
119