Пример #1
0
 def test_compact_rsa(self):
     jwe = JWE(algorithms=JWE_ALGORITHMS)
     s = jwe.serialize_compact({
         'alg': 'RSA-OAEP',
         'enc': 'A256GCM'
     }, 'hello', read_file_path('rsa_public.pem'))
     data = jwe.deserialize_compact(s, read_file_path('rsa_private.pem'))
     header, payload = data['header'], data['payload']
     self.assertEqual(payload, b'hello')
     self.assertEqual(header['alg'], 'RSA-OAEP')
Пример #2
0
    def __init__(self, algorithms=None, private_headers=None):
        if algorithms is None:
            self._jws = JWS(JWS_ALGORITHMS, private_headers)
            self._jwe = JWE(JWE_ALGORITHMS, private_headers)
        else:
            self._jws = JWS(None, private_headers)
            self._jwe = JWE(None, private_headers)

            if isinstance(algorithms, (tuple, list)):
                for algorithm in algorithms:
                    self.register_algorithm(algorithm)
            elif isinstance(algorithms, text_types):
                self.register_algorithm(algorithms)
Пример #3
0
 def test_aes_jwe(self):
     jwe = JWE(algorithms=JWE_ALGORITHMS)
     sizes = [128, 192, 256]
     _enc_choices = [
         'A128CBC-HS256', 'A192CBC-HS384', 'A256CBC-HS512', 'A128GCM',
         'A192GCM', 'A256GCM'
     ]
     for s in sizes:
         alg = 'A{}KW'.format(s)
         key = os.urandom(s // 8)
         for enc in _enc_choices:
             protected = {'alg': alg, 'enc': enc}
             data = jwe.serialize_compact(protected, b'hello', key)
             rv = jwe.deserialize_compact(data, key)
             self.assertEqual(rv['payload'], b'hello')
Пример #4
0
 def deserialize_and_decrypt(self, auth_code):
     return str(
         JWE(JWE_ALGORITHMS).deserialize_compact(
             auth_code, self.privkey_data)['payload'], 'utf-8')
Пример #5
0
 def encrypt_and_serialize(self, id_token):
     eprot = {'alg': 'RSA-OAEP', 'enc': 'A256GCM'}
     return JWE(JWE_ALGORITHMS).serialize_compact(eprot,
                                                  id_token.encode('utf-8'),
                                                  self.pubkey_data)
Пример #6
0
 def test_register_invalid_algorithms(self):
     jwe = JWE(algorithms=[])
     self.assertRaises(ValueError, jwe.register_algorithm,
                       JWS_ALGORITHMS[0])
Пример #7
0
 def test_ase_jwe_invalid_key(self):
     jwe = JWE(algorithms=JWE_ALGORITHMS)
     protected = {'alg': 'A128KW', 'enc': 'A128GCM'}
     self.assertRaises(ValueError, jwe.serialize_compact, protected,
                       b'hello', b'invalid-key')
Пример #8
0
 def test_not_enough_segments(self):
     s = 'a.b.c'
     jwe = JWE(algorithms=JWE_ALGORITHMS)
     self.assertRaises(errors.DecodeError, jwe.deserialize_compact, s, None)
Пример #9
0
class JWT(object):
    SENSITIVE_NAMES = ('password', 'token', 'secret', 'secret_key')
    # Thanks to sentry SensitiveDataFilter
    SENSITIVE_VALUES = re.compile(r'|'.join([
        # http://www.richardsramblings.com/regex/credit-card-numbers/
        r'\b(?:3[47]\d|(?:4\d|5[1-5]|65)\d{2}|6011)\d{12}\b',
        # various private keys
        r'-----BEGIN[A-Z ]+PRIVATE KEY-----.+-----END[A-Z ]+PRIVATE KEY-----',
        # social security numbers (US)
        r'^\b(?!(000|666|9))\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b',
    ]), re.DOTALL)

    def __init__(self, algorithms=None, private_headers=None):
        if algorithms is None:
            self._jws = JWS(JWS_ALGORITHMS, private_headers)
            self._jwe = JWE(JWE_ALGORITHMS, private_headers)
        else:
            self._jws = JWS(None, private_headers)
            self._jwe = JWE(None, private_headers)

            if isinstance(algorithms, (tuple, list)):
                for algorithm in algorithms:
                    self.register_algorithm(algorithm)
            elif isinstance(algorithms, text_types):
                self.register_algorithm(algorithms)

    def register_algorithm(self, algorithm):
        if isinstance(algorithm, text_types):
            algorithm = _AVAILABLE_ALGORITHMS.get(algorithm)

        if algorithm.TYPE == 'JWS':
            self._jws.register_algorithm(algorithm)
        elif algorithm.TYPE == 'JWE':
            self._jwe.register_algorithm(algorithm)

    def check_sensitive_data(self, payload):
        """Check if payload contains sensitive information."""
        for k in payload:
            # check claims key name
            if k in self.SENSITIVE_NAMES:
                raise InsecureClaimError(k)

            # check claims values
            v = payload[k]
            if isinstance(v, text_types) and self.SENSITIVE_VALUES.search(v):
                raise InsecureClaimError(k)

    def encode(self, header, payload, key, check=True):
        """Encode a JWT with the given header, payload and key.

        :param header: A dict of JWS header
        :param payload: A dict to be encoded
        :param key: key used to sign the signature
        :param check: check if sensitive data in payload
        :return: JWT
        """
        header['typ'] = 'JWT'

        for k in ['exp', 'iat', 'nbf']:
            # convert datetime into timestamp
            claim = payload.get(k)
            if isinstance(claim, datetime.datetime):
                payload[k] = calendar.timegm(claim.utctimetuple())

        if check:
            self.check_sensitive_data(payload)

        key = load_key(key, header, payload)
        text = to_bytes(json.dumps(payload, separators=(',', ':')))
        if 'enc' in header:
            return self._jwe.serialize_compact(header, text, key)
        else:
            return self._jws.serialize_compact(header, text, key)

    def decode(self, s, key, claims_cls=None,
               claims_options=None, claims_params=None):
        """Decode the JWS with the given key. This is similar with
        :meth:`verify`, except that it will raise BadSignatureError when
        signature doesn't match.

        :param s: text of JWT
        :param key: key used to verify the signature
        :param claims_cls: class to be used for JWT claims
        :param claims_options: `options` parameters for claims_cls
        :param claims_params: `params` parameters for claims_cls
        :return: claims_cls instance
        :raise: BadSignatureError
        """
        if claims_cls is None:
            claims_cls = JWTClaims

        key_func = create_key_func(key)

        s = to_bytes(s)
        dot_count = s.count(b'.')
        if dot_count == 2:
            data = self._jws.deserialize_compact(s, key_func, decode_payload)
        elif dot_count == 4:
            data = self._jwe.deserialize_compact(s, key_func, decode_payload)
        else:
            raise DecodeError('Invalid input segments length')
        return claims_cls(
            data['payload'], data['header'],
            options=claims_options,
            params=claims_params,
        )