Commit fcc6f34a authored by Simo Sorce's avatar Simo Sorce

Add support for JWT

JWT is the implementation of draft-ietf-oauth-json-web-token-32

Nesting is not explicitly supported for now.
Signed-off-by: default avatarSimo Sorce <simo@redhat.com>
parent c17c9b79
# Copyright (C) 2015 JWCrypto Project Contributors - see LICENSE file
from jwcrypto.common import json_encode
from jwcrypto.jws import JWS
from jwcrypto.jwe import JWE
class JWT(object):
def __init__(self, header=None, claims=None, jwt=None, key=None):
self._header = None
self._claims = None
self._token = None
if header:
self.header = header
if claims:
self.claims = claims
if jwt is not None:
self.deserialize(jwt, key)
@property
def header(self):
if self._header is None:
raise KeyError("'header' not set")
return self._header
@header.setter
def header(self, h):
if isinstance(h, dict):
self._header = json_encode(h)
else:
self._header = h
@property
def claims(self):
if self._claims is None:
raise KeyError("'claims' not set")
return self._claims
@claims.setter
def claims(self, c):
if isinstance(c, dict):
self._claims = json_encode(c)
else:
self._claims = c
@property
def token(self):
return self._token
@token.setter
def token(self, t):
if isinstance(t, JWS) or isinstance(t, JWE) or isinstance(t, JWT):
self._token = t
else:
raise TypeError("Invalid token type, must be one of JWS,JWE,JWT")
def make_signed_token(self, key):
t = JWS(self.claims)
t.add_signature(key, protected=self.header)
self.token = t
def make_encrypted_token(self, key):
t = JWE(self.claims, self.header)
t.add_recipient(key)
self.token = t
def deserialize(self, jwt, key=None):
c = jwt.count('.')
if c == 2:
self.token = JWS()
elif c == 4:
self.token = JWE()
else:
raise ValueError("Token format unrecognized")
# now deserialize and also decrypt/verify (or raise) if we
# have a key
self.token.deserialize(jwt, key)
if key is not None:
self.header = self.token.jose_header
self.claims = self.token.payload.decode('utf-8')
def serialize(self, compact=True):
return self.token.serialize(compact)
......@@ -6,6 +6,7 @@ from jwcrypto.common import json_decode, json_encode
from jwcrypto import jwk
from jwcrypto import jws
from jwcrypto import jwe
from jwcrypto import jwt
import unittest
# draft-ietf-jose-json-web-key-41 - A.1
......@@ -638,6 +639,71 @@ class TestJWE(unittest.TestCase):
E.deserialize(E_A5_ex)
# draft-ietf-oauth-json-web-token-32
A1_header = {
"alg": "RSA1_5",
"enc": "A128CBC-HS256"}
A1_claims = {
"iss": "joe",
"exp": 1300819380,
"http://example.com/is_root": True}
A1_token = \
"eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0." + \
"QR1Owv2ug2WyPBnbQrRARTeEk9kDO2w8qDcjiHnSJflSdv1iNqhWXaKH4MqAkQtM" + \
"oNfABIPJaZm0HaA415sv3aeuBWnD8J-Ui7Ah6cWafs3ZwwFKDFUUsWHSK-IPKxLG" + \
"TkND09XyjORj_CHAgOPJ-Sd8ONQRnJvWn_hXV1BNMHzUjPyYwEsRhDhzjAD26ima" + \
"sOTsgruobpYGoQcXUwFDn7moXPRfDE8-NoQX7N7ZYMmpUDkR-Cx9obNGwJQ3nM52" + \
"YCitxoQVPzjbl7WBuB7AohdBoZOdZ24WlN1lVIeh8v1K4krB8xgKvRU8kgFrEn_a" + \
"1rZgN5TiysnmzTROF869lQ." + \
"AxY8DCtDaGlsbGljb3RoZQ." + \
"MKOle7UQrG6nSxTLX6Mqwt0orbHvAKeWnDYvpIAeZ72deHxz3roJDXQyhxx0wKaM" + \
"HDjUEOKIwrtkHthpqEanSBNYHZgmNOV7sln1Eu9g3J8." + \
"fiK51VwhsxJ-siBMR-YFiA"
A2_token = \
"eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiY3R5IjoiSldU" + \
"In0." + \
"g_hEwksO1Ax8Qn7HoN-BVeBoa8FXe0kpyk_XdcSmxvcM5_P296JXXtoHISr_DD_M" + \
"qewaQSH4dZOQHoUgKLeFly-9RI11TG-_Ge1bZFazBPwKC5lJ6OLANLMd0QSL4fYE" + \
"b9ERe-epKYE3xb2jfY1AltHqBO-PM6j23Guj2yDKnFv6WO72tteVzm_2n17SBFvh" + \
"DuR9a2nHTE67pe0XGBUS_TK7ecA-iVq5COeVdJR4U4VZGGlxRGPLRHvolVLEHx6D" + \
"YyLpw30Ay9R6d68YCLi9FYTq3hIXPK_-dmPlOUlKvPr1GgJzRoeC9G5qCvdcHWsq" + \
"JGTO_z3Wfo5zsqwkxruxwA." + \
"UmVkbW9uZCBXQSA5ODA1Mg." + \
"VwHERHPvCNcHHpTjkoigx3_ExK0Qc71RMEParpatm0X_qpg-w8kozSjfNIPPXiTB" + \
"BLXR65CIPkFqz4l1Ae9w_uowKiwyi9acgVztAi-pSL8GQSXnaamh9kX1mdh3M_TT" + \
"-FZGQFQsFhu0Z72gJKGdfGE-OE7hS1zuBD5oEUfk0Dmb0VzWEzpxxiSSBbBAzP10" + \
"l56pPfAtrjEYw-7ygeMkwBl6Z_mLS6w6xUgKlvW6ULmkV-uLC4FUiyKECK4e3WZY" + \
"Kw1bpgIqGYsw2v_grHjszJZ-_I5uM-9RA8ycX9KqPRp9gc6pXmoU_-27ATs9XCvr" + \
"ZXUtK2902AUzqpeEUJYjWWxSNsS-r1TJ1I-FMJ4XyAiGrfmo9hQPcNBYxPz3GQb2" + \
"8Y5CLSQfNgKSGt0A4isp1hBUXBHAndgtcslt7ZoQJaKe_nNJgNliWtWpJ_ebuOpE" + \
"l8jdhehdccnRMIwAmU1n7SPkmhIl1HlSOpvcvDfhUN5wuqU955vOBvfkBOh5A11U" + \
"zBuo2WlgZ6hYi9-e3w29bR0C2-pp3jbqxEDw3iWaf2dc5b-LnR0FEYXvI_tYk5rd" + \
"_J9N0mg0tQ6RbpxNEMNoA9QWk5lgdPvbh9BaO195abQ." + \
"AVO9iT5AV4CzvDJCdhSFlQ"
class TestJWT(unittest.TestCase):
def test_A1(self):
key = jwk.JWK(**E_A2_key) # pylint: disable=star-args
# first encode/decode ourselves
T = jwt.JWT(A1_header, A1_claims)
T.make_encrypted_token(key)
token = T.serialize()
T.deserialize(token)
# then try the test vector
T = jwt.JWT(jwt=A1_token, key=key)
def test_A2(self):
sigkey = jwk.JWK(**A2_example['key']) # pylint: disable=star-args
Touter = jwt.JWT(jwt=A2_token, key=E_A2_ex['key'])
Tinner = jwt.JWT(jwt=Touter.claims, key=sigkey)
self.assertEqual(A1_claims, json_decode(Tinner.claims))
class ConformanceTests(unittest.TestCase):
def test_unknown_key_params(self):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment