def test_to_utf8(self): res = webapp2._to_utf8('ábcdéf'.decode('utf-8') if six.PY2 else 'ábcdéf') self.assertIsInstance(res, six.binary_type, True) res = webapp2._to_utf8('abcdef') self.assertIsInstance(res, six.binary_type, True)
def generate_token_string(self, action=None): """Generate a hash of the given token contents that can be verified. :param action: A string representing the action that the generated hash is valid for. This string is usually a URL. :returns: A string containing the hash contents of the given `action` and the contents of the `XSRFToken`. Can be verified with `verify_token_string`. The string is base64 encoded so it is safe to use in HTML forms without escaping. """ digest_maker = self._digest_maker() digest_maker.update(self.user_id) digest_maker.update(self._DELIMITER) if action: digest_maker.update(webapp2._to_utf8(action)) digest_maker.update(self._DELIMITER) digest_maker.update(self.current_time) return base64.urlsafe_b64encode( self._DELIMITER.join([ webapp2._to_utf8(digest_maker.hexdigest()), self.current_time ]) )
def test_to_utf8(self): res = webapp2._to_utf8( "ábcdéf".decode("utf-8") if six.PY2 else "ábcdéf") self.assertIsInstance(res, bytes, True) res = webapp2._to_utf8("abcdef") self.assertIsInstance(res, bytes, True)
def test_to_utf8(self): res = webapp2._to_utf8( 'ábcdéf'.decode('utf-8') if six.PY2 else 'ábcdéf') self.assertIsInstance(res, six.binary_type, True) res = webapp2._to_utf8('abcdef') self.assertIsInstance(res, six.binary_type, True)
def serialize(self, name, value): """Serializes a signed cookie value. :param name: Cookie name. :param value: Cookie value to be serialized. :returns: A serialized value ready to be stored in a cookie. """ name = webapp2._to_utf8(name) timestamp = webapp2._to_utf8(str(self._get_timestamp())) value = self._encode(value) signature = self._get_signature(name, value, timestamp) return b'|'.join([value, timestamp, signature])
def test_extra_request_methods(self): allowed_methods_backup = app.allowed_methods webdav_methods = ('VERSION-CONTROL', 'UNLOCK', 'PROPFIND') for method in webdav_methods: # It is still not possible to use WebDav methods... req = webapp2.Request.blank('/webdav') req.method = method rsp = req.get_response(app) self.assertEqual(rsp.status_int, 501) # Let's extend ALLOWED_METHODS with some WebDav methods. app.allowed_methods = tuple(app.allowed_methods) + webdav_methods # self.assertEqual( # sorted(webapp2.get_valid_methods(WebDavHandler)), # sorted(list(webdav_methods))) # Now we can use WebDav methods... for method in webdav_methods: req = webapp2.Request.blank('/webdav') req.method = method rsp = req.get_response(app) self.assertEqual(rsp.status_int, 200) self.assertEqual(rsp.body, webapp2._to_utf8('Method: %s' % method)) # Restore initial values. app.allowed_methods = allowed_methods_backup self.assertEqual(len(app.allowed_methods), 7)
def __init__(self, secret_key): """Initiliazes the serializer/deserializer. :param secret_key: A random string to be used as the HMAC secret for the cookie signature. """ self.secret_key = webapp2._to_utf8(secret_key)
def deserialize(self, name, value, max_age=None): """Deserializes a signed cookie value. :param name: Cookie name. :param value: A cookie value to be deserialized. :param max_age: Maximum age in seconds for a valid cookie. If the cookie is older than this, returns None. :returns: The deserialized secure cookie, or None if it is not valid. """ if not value: return None name = webapp2._to_utf8(name) value = webapp2._to_utf8(value) # Unquote for old WebOb. value = http_cookies._unquote(value) parts = value.split(b'|') if len(parts) != 3: return None signature = self._get_signature(name, parts[0], parts[1]) if not security.compare_hashes(parts[2], signature): logging.warning('Invalid cookie signature %r', value) return None if max_age is not None: if int(parts[1]) < self._get_timestamp() - max_age: logging.warning('Expired cookie %r', value) return None try: return self._decode(parts[0]) except Exception: logging.warning('Cookie value failed to be decoded: %r', parts[0]) return None
def __init__(self, user_id, secret, current_time=None): """Initializes the XSRFToken object. :param user_id: A string representing the user that the token will be valid for. :param secret: A string containing a secret key that will be used to seed the hash used by the :class:`XSRFToken`. :param current_time: An int representing the number of seconds since the epoch. Will be used by `verify_token_string` to check for token expiry. If `None` then the current time will be used. """ self.user_id = webapp2._to_utf8(user_id) self.secret = webapp2._to_utf8(secret) if current_time is None: self.current_time = int(time.time()) else: self.current_time = int(current_time) self.current_time = webapp2._to_utf8(str(self.current_time))
def hash_password(password, method, salt=None, pepper=None): """Hashes a password. Supports plaintext without salt, unsalted and salted passwords. In case salted passwords are used hmac is used. :param password: The password to be hashed. :param method: A method from ``hashlib``, e.g., `sha1` or `md5`, or `plain`. :param salt: A random salt string. :param pepper: A secret constant stored in the application code. :returns: A hashed password. This function was ported and adapted from `Werkzeug`_. """ if method == 'plain': return password password = webapp2._to_utf8(password) method = getattr(hashlib, method, None) if not method: return None if salt: h = hmac.new(webapp2._to_utf8(salt), password, method) else: h = method(password) if pepper: h = hmac.new( webapp2._to_utf8(pepper), webapp2._to_utf8(h.hexdigest()), method) return h.hexdigest()
def hash_password(password, method, salt=None, pepper=None): """Hashes a password. Supports plaintext without salt, unsalted and salted passwords. In case salted passwords are used hmac is used. :param password: The password to be hashed. :param method: A method from ``hashlib``, e.g., `sha1` or `md5`, or `plain`. :param salt: A random salt string. :param pepper: A secret constant stored in the application code. :returns: A hashed password. This function was ported and adapted from `Werkzeug`_. """ password = webapp2._to_utf8(password) if method == 'plain': return password method = getattr(hashlib, method, None) if not method: return None if salt: h = hmac.new(webapp2._to_utf8(salt), password, method) else: h = method(password) if pepper: h = hmac.new(webapp2._to_utf8(pepper), h.hexdigest(), method) return h.hexdigest()
def test_write(self): var_1 = NoStringOrUnicodeConversion() var_2 = StringConversion() var_3 = UnicodeConversion() rsp = webapp2.Response() rsp.write(var_1) rsp.write(var_2) rsp.write(var_3) self.assertEqual(rsp.body, webapp2._to_utf8('%rfoobar' % var_1)) rsp = webapp2.Response() rsp.write(var_1) rsp.write(var_3) rsp.write(var_2) self.assertEqual(rsp.body, webapp2._to_utf8('%rbarfoo' % var_1)) rsp = webapp2.Response() rsp.write(var_2) rsp.write(var_1) rsp.write(var_3) self.assertEqual(rsp.body, webapp2._to_utf8('foo%rbar' % var_1)) rsp = webapp2.Response() rsp.write(var_2) rsp.write(var_3) rsp.write(var_1) self.assertEqual(rsp.body, webapp2._to_utf8('foobar%r' % var_1)) rsp = webapp2.Response() rsp.write(var_3) rsp.write(var_1) rsp.write(var_2) self.assertEqual(rsp.body, webapp2._to_utf8('bar%rfoo' % var_1)) rsp = webapp2.Response() rsp.write(var_3) rsp.write(var_2) rsp.write(var_1) self.assertEqual(rsp.body, webapp2._to_utf8('barfoo%r' % var_1))
def verify_token_string(self, token_string, action=None, timeout=None, current_time=None): """Generate a hash of the given token contents that can be verified. :param token_string: A string containing the hashed token (generated by `generate_token_string`). :param action: A string containing the action that is being verified. :param timeout: An int or float representing the number of seconds that the token is valid for. If None then tokens are valid forever. :current_time: An int representing the number of seconds since the epoch. Will be used by to check for token expiry if `timeout` is set. If `None` then the current time will be used. :raises: XSRFTokenMalformed if the given token_string cannot be parsed. XSRFTokenExpiredException if the given token string is expired. XSRFTokenInvalid if the given token string does not match the contents of the `XSRFToken`. """ import binascii try: decoded_token_string = base64.urlsafe_b64decode( webapp2._to_utf8(token_string)) except (TypeError, binascii.Error): raise XSRFTokenMalformed() split_token = decoded_token_string.split(self._DELIMITER) if len(split_token) != 2: raise XSRFTokenMalformed() try: token_time = int(split_token[1]) except ValueError: raise XSRFTokenMalformed() if timeout is not None: if current_time is None: current_time = time.time() # If an attacker modifies the plain text time then # it will not match the hashed time so this check is sufficient. if (token_time + timeout) < current_time: raise XSRFTokenExpiredException() expected_token = XSRFToken(self.user_id, self.secret, token_time) expected_token_string = expected_token.generate_token_string(action) if len(expected_token_string) != len(token_string): raise XSRFTokenInvalid() # Compare the two strings in constant time to prevent timing attacks. different = 0 for a, b in zip( webapp2._to_basestring(token_string), webapp2._to_basestring(expected_token_string)): different |= ord(a) ^ ord(b) if different: raise XSRFTokenInvalid()
def _get_signature(self, *parts): """Generates an HMAC signature.""" signature = hmac.new(self.secret_key, digestmod=hashlib.sha1) signature.update(b'|'.join(parts)) return webapp2._to_utf8(signature.hexdigest())
def test_to_utf8(self): res = webapp2._to_utf8('ábcdéf'.decode('utf-8')) self.assertEqual(isinstance(res, str), True) res = webapp2._to_utf8('abcdef') self.assertEqual(isinstance(res, str), True)
def verify_token_string(self, token_string, action=None, timeout=None, current_time=None): """Generate a hash of the given token contents that can be verified. :param token_string: A string containing the hashed token (generated by `generate_token_string`). :param action: A string containing the action that is being verified. :param timeout: An int or float representing the number of seconds that the token is valid for. If None then tokens are valid forever. :current_time: An int representing the number of seconds since the epoch. Will be used by to check for token expiry if `timeout` is set. If `None` then the current time will be used. :raises: XSRFTokenMalformed if the given token_string cannot be parsed. XSRFTokenExpiredException if the given token string is expired. XSRFTokenInvalid if the given token string does not match the contents of the `XSRFToken`. """ import binascii try: decoded_token_string = base64.urlsafe_b64decode( webapp2._to_utf8(token_string)) except (TypeError, binascii.Error): raise XSRFTokenMalformed() split_token = decoded_token_string.split(self._DELIMITER) if len(split_token) != 2: raise XSRFTokenMalformed() try: token_time = int(split_token[1]) except ValueError: raise XSRFTokenMalformed() if timeout is not None: if current_time is None: current_time = time.time() # If an attacker modifies the plain text time then # it will not match the hashed time so this check is sufficient. if (token_time + timeout) < current_time: raise XSRFTokenExpiredException() expected_token = XSRFToken(self.user_id, self.secret, token_time) expected_token_string = expected_token.generate_token_string(action) if len(expected_token_string) != len(token_string): raise XSRFTokenInvalid() # Compare the two strings in constant time to prevent timing attacks. different = 0 for a, b in zip(webapp2._to_basestring(token_string), webapp2._to_basestring(expected_token_string)): different |= ord(a) ^ ord(b) if different: raise XSRFTokenInvalid()