예제 #1
0
 def test_key_storage(self):
     # Explicitly clear our cache.
     KeyStorage._cached = (None, None)
     # Call get method to retrieve our singleton KeyStorage.
     ks = KeyStorage.get()
     self.assertTrue(ks is not None)
     # We should cache this object, so another call will return the
     # same object.
     self.assertTrue(ks is KeyStorage.get())
     # Now advance mock time enough to expire our cache.
     self.now += 365 * 24 * 60 * 60  # 1 year should be enough time
     self.assertTrue(ks is not KeyStorage.get())
예제 #2
0
 def test_key_storage(self):
     # Explicitly clear our cache.
     KeyStorage._cached = (None, None)
     # Call get method to retrieve our singleton KeyStorage.
     ks = KeyStorage.get()
     self.assertTrue(ks is not None)
     # We should cache this object, so another call will return the
     # same object.
     self.assertTrue(ks is KeyStorage.get())
     # Now advance mock time enough to expire our cache.
     self.now += 365 * 24 * 60 * 60  # 1 year should be enough time
     self.assertTrue(ks is not KeyStorage.get())
예제 #3
0
def _create_security_token(user):
    """Create a CHIRP security token.

    Args:
      user: A User object.

    Returns:
      A string containing an encrypted security token that encodes
      the user's email address as well as a timestamp.
    """
    timestamp = int(time.time())
    plaintext = "%x %s" % (timestamp, user.email)
    nearest_mult_of_16 = 16 * ((len(plaintext) + 15) // 16)
    # Pad plaintest with whitespace to make the length a multiple of 16,
    # as this is a requirement of AES encryption.
    plaintext = plaintext.rjust(nearest_mult_of_16, ' ')
    if _DISABLE_CRYPTO:
        body = plaintext
        sig = "sig"
    else:
        key_storage = KeyStorage.get()
        body = AES.new(key_storage.aes_key, AES.MODE_CBC).encrypt(plaintext)
        hmac_key = key_storage.hmac_key
        if type(hmac_key) == unicode:
            # Crypto requires byte strings
            hmac_key = hmac_key.encode('utf8')
        sig = HMAC.HMAC(key=hmac_key, msg=body).hexdigest()
    return '%s:%s' % (sig, body)
예제 #4
0
def _parse_security_token(token):
    """Parse a CHIRP security token.

    Returns:
      A Credentials object, or None if the token is not valid.
      If a Credentials object is returned, its "user" field will not
      be set.
    """
    if not token:
        return None
    if ':' not in token:
        logging.warn('Malformed token: no signature separator')
        return None
    sig, body = token.split(':', 1)
    if _DISABLE_CRYPTO:
        plaintext = body
    else:
        key_storage = KeyStorage.get()
        hmac_key = key_storage.hmac_key
        if type(hmac_key) == unicode:
            # Crypto requires byte strings
            hmac_key = hmac_key.encode('utf8')
        computed_sig = HMAC.HMAC(key=hmac_key,
                                 msg=body).hexdigest()
        if sig != computed_sig:
            logging.warn('Malformed token: invalid signature')
            return None
        try:
            plaintext = AES.new(key_storage.aes_key,
                                AES.MODE_CBC).decrypt(body)
        except ValueError:
            logging.warn('Malformed token: wrong size')
            return None
    # Remove excess whitespace.
    plaintext = plaintext.strip()
    # The plaintext should contain at least one space.
    if ' ' not in plaintext:
        logging.warn('Malformed token: bad contents')
        return None
    parts = plaintext.split(' ')
    if len(parts) != 2:
        logging.warn('Malformed token: bad structure')
        return None
    timestamp, email = parts
    try:
        timestamp = int(timestamp, 16)
    except ValueError:
        logging.warn('Malformed token: bad timestamp')
        return None
    # Reject tokens that are too old or which have time-traveled.  We
    # allow for 1s of clock skew.
    age_s = time.time() - timestamp
    if age_s < -1 or age_s > _TOKEN_TIMEOUT_S:
        logging.warn('Malformed token: expired (age=%ds)', age_s)
        return None
    cred = _Credentials()
    cred.email = email
    cred.security_token_is_stale = (age_s > 0.5 * _TOKEN_TIMEOUT_S)
    return cred