Exemple #1
0
def verify_signed_jwt_with_certs(jwt, certs, audience=None):
    """Verify a JWT against public certs.

    See http://self-issued.info/docs/draft-jones-json-web-token.html.

    Args:
        jwt: string, A JWT.
        certs: dict, Dictionary where values of public keys in PEM format.
        audience: string, The audience, 'aud', that this JWT should contain. If
                  None then the JWT's 'aud' parameter is not verified.

    Returns:
        dict, The deserialized JSON payload in the JWT.

    Raises:
        AppIdentityError: if any checks are failed.
    """
    jwt = _helpers._to_bytes(jwt)

    if jwt.count(b'.') != 2:
        raise AppIdentityError(
            'Wrong number of segments in token: {0}'.format(jwt))

    header, payload, signature = jwt.split(b'.')
    message_to_sign = header + b'.' + payload
    signature = _helpers._urlsafe_b64decode(signature)

    # Parse token.
    payload_bytes = _helpers._urlsafe_b64decode(payload)
    try:
        payload_dict = json.loads(_helpers._from_bytes(payload_bytes))
    except:
        raise AppIdentityError('Can\'t parse token: {0}'.format(payload_bytes))

    # Verify that the signature matches the message.
    _verify_signature(message_to_sign, signature, certs.values())

    # Verify the issued at and created times in the payload.
    _verify_time_range(payload_dict)

    # Check audience.
    _check_audience(payload_dict, audience)

    return payload_dict
    def from_string(key_pem, is_x509_cert):
        """Construct a Verified instance from a string.

        Args:
            key_pem: string, public key in PEM format.
            is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it
                          is expected to be an RSA key in PEM format.

        Returns:
            Verifier instance.
        """
        if is_x509_cert:
            key_pem = _helpers._to_bytes(key_pem)
            pemLines = key_pem.replace(b' ', b'').split()
            certDer = _helpers._urlsafe_b64decode(b''.join(pemLines[1:-1]))
            certSeq = DerSequence()
            certSeq.decode(certDer)
            tbsSeq = DerSequence()
            tbsSeq.decode(certSeq[0])
            pubkey = RSA.importKey(tbsSeq[6])
        else:
            pubkey = RSA.importKey(key_pem)
        return PyCryptoVerifier(pubkey)
    def from_string(key_pem, is_x509_cert):
        """Construct a Verified instance from a string.

        Args:
            key_pem: string, public key in PEM format.
            is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it
                          is expected to be an RSA key in PEM format.

        Returns:
            Verifier instance.
        """
        if is_x509_cert:
            key_pem = _to_bytes(key_pem)
            pemLines = key_pem.replace(b' ', b'').split()
            certDer = _urlsafe_b64decode(b''.join(pemLines[1:-1]))
            certSeq = DerSequence()
            certSeq.decode(certDer)
            tbsSeq = DerSequence()
            tbsSeq.decode(certSeq[0])
            pubkey = RSA.importKey(tbsSeq[6])
        else:
            pubkey = RSA.importKey(key_pem)
        return PyCryptoVerifier(pubkey)
Exemple #4
0
 def test_valid_input_unicode(self):
   test_string = b'ZGVhZGJlZWY'
   result = _urlsafe_b64decode(test_string)
   self.assertEqual(result, b'deadbeef')
Exemple #5
0
 def test_valid_input_bytes(self):
     test_string = b'ZGVhZGJlZWY'
     result = _helpers._urlsafe_b64decode(test_string)
     self.assertEqual(result, b'deadbeef')
Exemple #6
0
 def test_bad_input(self):
     import binascii
     bad_string = b'+'
     with self.assertRaises((TypeError, binascii.Error)):
         _helpers._urlsafe_b64decode(bad_string)
Exemple #7
0
def verify_signed_jwt_with_certs(jwt, certs, audience):
  """Verify a JWT against public certs.

  See http://self-issued.info/docs/draft-jones-json-web-token.html.

  Args:
    jwt: string, A JWT.
    certs: dict, Dictionary where values of public keys in PEM format.
    audience: string, The audience, 'aud', that this JWT should contain. If
      None then the JWT's 'aud' parameter is not verified.

  Returns:
    dict, The deserialized JSON payload in the JWT.

  Raises:
    AppIdentityError if any checks are failed.
  """
  jwt = _to_bytes(jwt)
  segments = jwt.split(b'.')

  if len(segments) != 3:
    raise AppIdentityError('Wrong number of segments in token: %s' % jwt)
  signed = segments[0] + b'.' + segments[1]

  signature = _urlsafe_b64decode(segments[2])

  # Parse token.
  json_body = _urlsafe_b64decode(segments[1])
  try:
    parsed = json.loads(json_body.decode('utf-8'))
  except:
    raise AppIdentityError('Can\'t parse token: %s' % json_body)

  # Check signature.
  verified = False
  for pem in certs.values():
    verifier = Verifier.from_string(pem, True)
    if verifier.verify(signed, signature):
      verified = True
      break
  if not verified:
    raise AppIdentityError('Invalid token signature: %s' % jwt)

  # Check creation timestamp.
  iat = parsed.get('iat')
  if iat is None:
    raise AppIdentityError('No iat field in token: %s' % json_body)
  earliest = iat - CLOCK_SKEW_SECS

  # Check expiration timestamp.
  now = int(time.time())
  exp = parsed.get('exp')
  if exp is None:
    raise AppIdentityError('No exp field in token: %s' % json_body)
  if exp >= now + MAX_TOKEN_LIFETIME_SECS:
    raise AppIdentityError('exp field too far in future: %s' % json_body)
  latest = exp + CLOCK_SKEW_SECS

  if now < earliest:
    raise AppIdentityError('Token used too early, %d < %d: %s' %
                           (now, earliest, json_body))
  if now > latest:
    raise AppIdentityError('Token used too late, %d > %d: %s' %
                           (now, latest, json_body))

  # Check audience.
  if audience is not None:
    aud = parsed.get('aud')
    if aud is None:
      raise AppIdentityError('No aud field in token: %s' % json_body)
    if aud != audience:
      raise AppIdentityError('Wrong recipient, %s != %s: %s' %
                             (aud, audience, json_body))

  return parsed
Exemple #8
0
def verify_signed_jwt_with_certs(jwt, certs, audience):
    """Verify a JWT against public certs.

  See http://self-issued.info/docs/draft-jones-json-web-token.html.

  Args:
    jwt: string, A JWT.
    certs: dict, Dictionary where values of public keys in PEM format.
    audience: string, The audience, 'aud', that this JWT should contain. If
      None then the JWT's 'aud' parameter is not verified.

  Returns:
    dict, The deserialized JSON payload in the JWT.

  Raises:
    AppIdentityError if any checks are failed.
  """
    jwt = _to_bytes(jwt)
    segments = jwt.split(b'.')

    if len(segments) != 3:
        raise AppIdentityError('Wrong number of segments in token: %s' % jwt)
    signed = segments[0] + b'.' + segments[1]

    signature = _urlsafe_b64decode(segments[2])

    # Parse token.
    json_body = _urlsafe_b64decode(segments[1])
    try:
        parsed = json.loads(json_body.decode('utf-8'))
    except:
        raise AppIdentityError('Can\'t parse token: %s' % json_body)

    # Check signature.
    verified = False
    for pem in certs.values():
        verifier = Verifier.from_string(pem, True)
        if verifier.verify(signed, signature):
            verified = True
            break
    if not verified:
        raise AppIdentityError('Invalid token signature: %s' % jwt)

    # Check creation timestamp.
    iat = parsed.get('iat')
    if iat is None:
        raise AppIdentityError('No iat field in token: %s' % json_body)
    earliest = iat - CLOCK_SKEW_SECS

    # Check expiration timestamp.
    now = int(time.time())
    exp = parsed.get('exp')
    if exp is None:
        raise AppIdentityError('No exp field in token: %s' % json_body)
    if exp >= now + MAX_TOKEN_LIFETIME_SECS:
        raise AppIdentityError('exp field too far in future: %s' % json_body)
    latest = exp + CLOCK_SKEW_SECS

    if now < earliest:
        raise AppIdentityError('Token used too early, %d < %d: %s' %
                               (now, earliest, json_body))
    if now > latest:
        raise AppIdentityError('Token used too late, %d > %d: %s' %
                               (now, latest, json_body))

    # Check audience.
    if audience is not None:
        aud = parsed.get('aud')
        if aud is None:
            raise AppIdentityError('No aud field in token: %s' % json_body)
        if aud != audience:
            raise AppIdentityError('Wrong recipient, %s != %s: %s' %
                                   (aud, audience, json_body))

    return parsed
Exemple #9
0
 def test_valid_input_unicode(self):
     test_string = u'ZGVhZGJlZWY'
     result = _helpers._urlsafe_b64decode(test_string)
     self.assertEqual(result, self.DEADBEEF_DECODED)
 def test_valid_input_bytes(self):
     test_string = b"ZGVhZGJlZWY"
     result = _urlsafe_b64decode(test_string)
     self.assertEqual(result, b"deadbeef")
Exemple #11
0
 def test_valid_input_unicode(self):
     test_string = u'ZGVhZGJlZWY'
     result = _helpers._urlsafe_b64decode(test_string)
     self.assertEqual(result, self.DEADBEEF_DECODED)