Skip to content

Commit 6b77d37

Browse files
committed
Change token() method to property
- Add lots of type hints - Add docs about how to get serialized token value - More docs
1 parent ea63f60 commit 6b77d37

File tree

3 files changed

+71
-27
lines changed

3 files changed

+71
-27
lines changed

doc/source/index.rst

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,28 @@ Creating and signing new tokens
6565
token.set_claim('sub', 42)
6666
token.set_claim('foo', 'bar')
6767
68-
# Sign token with private key
69-
token.sign()
68+
# Sign token with private key, and get serialized token back
69+
token_str = token.sign()
70+
71+
# You can also get the serialized token from the token objectt by accessing
72+
# the token_str property
73+
token_str = token.token_str
74+
75+
As a convenience, if you use the token object in string or boolean context it
76+
will do *the right thing™*.
77+
78+
.. code:: python
79+
80+
# Token in string context gives you the serialized token
81+
token_str = str(token)
82+
83+
# Token in boolean context gives you the validity of the token
84+
is_valid = bool(token)
85+
86+
# Parse token from string, and do stuff with it, if it is valid
87+
token = MySWT(http_header_value)
88+
if token:
89+
# Do stuff with the valid token
7090
7191
API Reference
7292
-------------

src/swt/__init__.py

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,21 @@ class SWT:
2020
extend the algorithm specific sub class. Currently only RSA SHA256 is implemented.
2121
"""
2222
# Supported algorithm constants
23-
ALGORITHM_RSA_SHA256 = 'RSASHA256'
24-
ALGORITHM_HMAC_SHA256 = 'HMACSHA256'
23+
ALGORITHM_RSA_SHA256 : str = 'RSASHA256'
24+
ALGORITHM_HMAC_SHA256: str = 'HMACSHA256'
2525

2626
# Internals to override Selected algorithm
27-
default_ttl = 3600
27+
default_ttl: int = 3600
2828

2929
# Standard claim names
30-
iss_claim = 'Issuer'
31-
exp_claim = 'ExpiresOn'
32-
aud_claim = 'Audience'
30+
iss_claim: str = 'Issuer'
31+
exp_claim: str = 'ExpiresOn'
32+
aud_claim: str = 'Audience'
3333

3434
# Extra claim names modeled after JWT claim names
35-
sub_claim = 'sub'
36-
iat_claim = 'iat'
37-
sid_claim = 'sid'
35+
sub_claim: str = 'sub'
36+
iat_claim: str = 'iat'
37+
sid_claim: str = 'sid'
3838

3939
def __init__(self, token_str: typing.Optional[str] = None):
4040
"""Create new SWT"""
@@ -47,16 +47,24 @@ def __init__(self, token_str: typing.Optional[str] = None):
4747

4848
# If called with a token, set and verify
4949
if token_str is not None:
50-
self.token(token_str)
50+
self.token_str = token_str
5151

5252
@property
5353
def is_valid(self):
54-
"""Check if the SWT is both sign and not expired"""
54+
"""Check if the SWT is both sign and not expired
55+
56+
Returns:
57+
bool: token validity
58+
"""
5559
return self.is_signed and not self.is_expired
5660

5761
@property
5862
def is_expired(self):
59-
"""Check if the SWT is expired"""
63+
"""Check if the SWT is expired
64+
65+
Returns:
66+
bool: is expired
67+
"""
6068
if not self.is_signed:
6169
return True
6270
return int(self._token_claims.get(self.__class__.exp_claim, 0)) < int(time.time())
@@ -89,22 +97,29 @@ def __bool__(self):
8997
def __str__(self):
9098
return self._token_str
9199

92-
def get_public_key(self):
100+
def get_public_key(self) -> str:
93101
"""Implement this in your own subclass to find and load the public key by issuer"""
94102
raise NotImplementedError("Please implement your own get_public_key() method")
95103

96-
def get_private_key(self):
104+
def get_private_key(self) -> str:
97105
"""Implement this in your own subclass to find and load the private key by issuer"""
98106
raise NotImplementedError("Please implement your own get_public_key() method")
99107

100-
def set_claim(self, claim, value):
108+
def set_claim(self, claim: str, value: str):
101109
self._token_claims[claim] = value
102110

103-
def get_claim(self, claim):
111+
def get_claim(self, claim: str) -> str:
104112
return self._token_claims[claim]
105113

106-
def token(self, token: str):
107-
"""Set token from string"""
114+
@property
115+
def token_str(self) -> str:
116+
"""Token as serialized string"""
117+
return self._token_str
118+
119+
@token_str.setter
120+
def token_str(self, token: str):
121+
"""Token as string"""
122+
108123
# Allow caller to take http header and parse it directly to us
109124
self._token_str = str(token).replace('Bearer ', '')
110125

@@ -128,13 +143,21 @@ def algorithm(self):
128143
"""The algorithm used for the SWT"""
129144
raise NotImplementedError("Please implement algorithm specific algorithm @property method")
130145

131-
def sign(self):
132-
"""Algorithm specific sign() method"""
146+
def sign(self) -> str:
147+
"""Algorithm specific sign() method
148+
149+
Returns:
150+
str: signed token
151+
"""
133152
raise NotImplementedError("Please implement algorithm specific sign() method")
134153

135154
@property
136155
def is_signed(self):
137-
"""Algorithm specific is_signed() property"""
156+
"""Algorithm specific is_signed() property
157+
158+
Returns:
159+
bool: signed status
160+
"""
138161
raise NotImplementedError("Please implement algorithm specific is_signed @property method")
139162

140163
class SWT_RSA_SHA256(SWT):
@@ -156,8 +179,9 @@ def sign(self):
156179
self._token_signature_str = quote(b64encode(self._token_signature))
157180
self._token_str = self._token_claims_str + f'&{self.algorithm}=' + self._token_signature_str
158181

182+
159183
@property
160-
def is_signed(self):
184+
def is_signed(self) -> bool:
161185
# Give on beforehand if we don't have a signature
162186
if not self._token_signature:
163187
return False

tests/test_swt_rsa_sha256.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,14 @@ def test_valid_swt_from_string():
7575
assert token.is_valid, "Token is valid (both signed and not expired)"
7676
assert bool(token) == True, "Token with valid signature has a boolean value of True"
7777
assert token.get_claim('foo') == 'bar', "Token has claim foo with value of bar"
78-
78+
assert token.token_str == str(token), "Token has string value"
7979

8080
def test_swt_broken_signature():
8181
# Remove one character from token signature
8282
broken_token_str = pytest.test_token_str[0:len(pytest.test_token_str)-5] + pytest.test_token_str[-4:]
8383

8484
token = MySWT()
85-
token.token(broken_token_str)
85+
token.token_str = broken_token_str
8686
assert token.is_signed == False, "Token has broken signed (we broke it on purpose)"
8787
assert bool(token) == False, "Token with invalid signature has a boolean value of False"
8888
assert token.is_expired == True, "Token is expired, even if date is ok"
@@ -92,7 +92,7 @@ def test_swt_no_signature():
9292
# Remove signature from valid token, and create new invalid token
9393
token = MySWT()
9494
broken_token_str, _ = pytest.test_token_str.rsplit(f'&{token.algorithm}=')
95-
token.token(broken_token_str)
95+
token.token_str = broken_token_str
9696

9797
assert token.is_signed == False, "Token has broken signed (we broke it on purpose)"
9898
assert bool(token) == False, "Token with invalid signature has a boolean value of False"

0 commit comments

Comments
 (0)