9
9
10
10
logger = logging .getLogger (__name__ )
11
11
12
- class Signer (object ):
13
- def sign_assertion (
14
- self , audience , issuer , subject , expires_at ,
12
+ class AssertionCreator (object ):
13
+ def create_normal_assertion (
14
+ self , audience , issuer , subject , expires_at = None , expires_in = 600 ,
15
15
issued_at = None , assertion_id = None , ** kwargs ):
16
- # Names are defined in https://tools.ietf.org/html/rfc7521#section-5
16
+ """Create an assertion in bytes, based on the provided claims.
17
+
18
+ All parameter names are defined in https://tools.ietf.org/html/rfc7521#section-5
19
+ except the expires_in is defined here as lifetime-in-seconds,
20
+ which will be automatically translated into expires_at in UTC.
21
+ """
17
22
raise NotImplementedError ("Will be implemented by sub-class" )
18
23
24
+ def create_regenerative_assertion (
25
+ self , audience , issuer , subject = None , expires_in = 600 , ** kwargs ):
26
+ """Create an assertion as a callable,
27
+ which will then compute the assertion later when necessary.
28
+
29
+ This is a useful optimization to reuse the client assertion.
30
+ """
31
+ return AutoRefresher ( # Returns a callable
32
+ lambda a = audience , i = issuer , s = subject , e = expires_in , kwargs = kwargs :
33
+ self .create_normal_assertion (a , i , s , expires_in = e , ** kwargs ),
34
+ expires_in = max (expires_in - 60 , 0 ))
35
+
36
+
37
+ class AutoRefresher (object ):
38
+ """Cache the output of a factory, and auto-refresh it when necessary. Usage::
19
39
20
- class JwtSigner (Signer ):
40
+ r = AutoRefresher(time.time, expires_in=5)
41
+ for i in range(15):
42
+ print(r()) # the timestamp change only after every 5 seconds
43
+ time.sleep(1)
44
+ """
45
+ def __init__ (self , factory , expires_in = 540 ):
46
+ self ._factory = factory
47
+ self ._expires_in = expires_in
48
+ self ._buf = {}
49
+ def __call__ (self ):
50
+ EXPIRES_AT , VALUE = "expires_at" , "value"
51
+ now = time .time ()
52
+ if self ._buf .get (EXPIRES_AT , 0 ) <= now :
53
+ logger .debug ("Regenerating new assertion" )
54
+ self ._buf = {VALUE : self ._factory (), EXPIRES_AT : now + self ._expires_in }
55
+ else :
56
+ logger .debug ("Reusing still valid assertion" )
57
+ return self ._buf .get (VALUE )
58
+
59
+
60
+ class JwtAssertionCreator (AssertionCreator ):
21
61
def __init__ (self , key , algorithm , sha1_thumbprint = None , headers = None ):
22
- """Create a signer .
62
+ """Construct a Jwt assertion creator .
23
63
24
64
Args:
25
65
@@ -37,11 +77,11 @@ def __init__(self, key, algorithm, sha1_thumbprint=None, headers=None):
37
77
self .headers ["x5t" ] = base64 .urlsafe_b64encode (
38
78
binascii .a2b_hex (sha1_thumbprint )).decode ()
39
79
40
- def sign_assertion (
41
- self , audience , issuer , subject = None , expires_at = None ,
80
+ def create_normal_assertion (
81
+ self , audience , issuer , subject = None , expires_at = None , expires_in = 600 ,
42
82
issued_at = None , assertion_id = None , not_before = None ,
43
83
additional_claims = None , ** kwargs ):
44
- """Sign a JWT Assertion.
84
+ """Create a JWT Assertion.
45
85
46
86
Parameters are defined in https://tools.ietf.org/html/rfc7523#section-3
47
87
Key-value pairs in additional_claims will be added into payload as-is.
@@ -51,7 +91,7 @@ def sign_assertion(
51
91
'aud' : audience ,
52
92
'iss' : issuer ,
53
93
'sub' : subject or issuer ,
54
- 'exp' : expires_at or (now + 10 * 60 ), # 10 minutes
94
+ 'exp' : expires_at or (now + expires_in ),
55
95
'iat' : issued_at or now ,
56
96
'jti' : assertion_id or str (uuid .uuid4 ()),
57
97
}
@@ -68,3 +108,9 @@ def sign_assertion(
68
108
'See https://pyjwt.readthedocs.io/en/latest/installation.html#cryptographic-dependencies-optional' )
69
109
raise
70
110
111
+
112
+ # Obsolete. For backward compatibility. They will be removed in future versions.
113
+ Signer = AssertionCreator # For backward compatibility
114
+ JwtSigner = JwtAssertionCreator # For backward compatibility
115
+ JwtSigner .sign_assertion = JwtAssertionCreator .create_normal_assertion # For backward compatibility
116
+
0 commit comments