23
23
from signedjson .key import encode_verify_key_base64 , get_verify_key
24
24
25
25
from twisted .internet import defer
26
+ from twisted .internet .defer import Deferred , ensureDeferred
26
27
27
28
from synapse .api .errors import SynapseError
28
29
from synapse .crypto import keyring
33
34
)
34
35
from synapse .logging .context import (
35
36
LoggingContext ,
36
- PreserveLoggingContext ,
37
37
current_context ,
38
38
make_deferred_yieldable ,
39
39
)
@@ -68,54 +68,40 @@ def sign_response(self, res):
68
68
69
69
70
70
class KeyringTestCase (unittest .HomeserverTestCase ):
71
- def make_homeserver (self , reactor , clock ):
72
- self .mock_perspective_server = MockPerspectiveServer ()
73
- self .http_client = Mock ()
74
-
75
- config = self .default_config ()
76
- config ["trusted_key_servers" ] = [
77
- {
78
- "server_name" : self .mock_perspective_server .server_name ,
79
- "verify_keys" : self .mock_perspective_server .get_verify_keys (),
80
- }
81
- ]
82
-
83
- return self .setup_test_homeserver (
84
- handlers = None , http_client = self .http_client , config = config
85
- )
86
-
87
- def check_context (self , _ , expected ):
71
+ def check_context (self , val , expected ):
88
72
self .assertEquals (getattr (current_context (), "request" , None ), expected )
73
+ return val
89
74
90
75
def test_verify_json_objects_for_server_awaits_previous_requests (self ):
91
- key1 = signedjson .key .generate_signing_key (1 )
76
+ mock_fetcher = keyring .KeyFetcher ()
77
+ mock_fetcher .get_keys = Mock ()
78
+ kr = keyring .Keyring (self .hs , key_fetchers = (mock_fetcher ,))
92
79
93
- kr = keyring .Keyring (self .hs )
80
+ # a signed object that we are going to try to validate
81
+ key1 = signedjson .key .generate_signing_key (1 )
94
82
json1 = {}
95
83
signedjson .sign .sign_json (json1 , "server10" , key1 )
96
84
97
- persp_resp = {
98
- "server_keys" : [
99
- self .mock_perspective_server .get_signed_key (
100
- "server10" , signedjson .key .get_verify_key (key1 )
101
- )
102
- ]
103
- }
104
- persp_deferred = defer .Deferred ()
85
+ # start off a first set of lookups. We make the mock fetcher block until this
86
+ # deferred completes.
87
+ first_lookup_deferred = Deferred ()
88
+
89
+ async def first_lookup_fetch (keys_to_fetch ):
90
+ self .assertEquals (current_context ().request , "context_11" )
91
+ self .assertEqual (keys_to_fetch , {"server10" : {get_key_id (key1 ): 0 }})
105
92
106
- async def get_perspectives (** kwargs ):
107
- self .assertEquals (current_context ().request , "11" )
108
- with PreserveLoggingContext ():
109
- await persp_deferred
110
- return persp_resp
93
+ await make_deferred_yieldable (first_lookup_deferred )
94
+ return {
95
+ "server10" : {
96
+ get_key_id (key1 ): FetchKeyResult (get_verify_key (key1 ), 100 )
97
+ }
98
+ }
111
99
112
- self . http_client . post_json . side_effect = get_perspectives
100
+ mock_fetcher . get_keys . side_effect = first_lookup_fetch
113
101
114
- # start off a first set of lookups
115
- @defer .inlineCallbacks
116
- def first_lookup ():
117
- with LoggingContext ("11" ) as context_11 :
118
- context_11 .request = "11"
102
+ async def first_lookup ():
103
+ with LoggingContext ("context_11" ) as context_11 :
104
+ context_11 .request = "context_11"
119
105
120
106
res_deferreds = kr .verify_json_objects_for_server (
121
107
[("server10" , json1 , 0 , "test10" ), ("server11" , {}, 0 , "test11" )]
@@ -124,53 +110,59 @@ def first_lookup():
124
110
# the unsigned json should be rejected pretty quickly
125
111
self .assertTrue (res_deferreds [1 ].called )
126
112
try :
127
- yield res_deferreds [1 ]
113
+ await res_deferreds [1 ]
128
114
self .assertFalse ("unsigned json didn't cause a failure" )
129
115
except SynapseError :
130
116
pass
131
117
132
118
self .assertFalse (res_deferreds [0 ].called )
133
119
res_deferreds [0 ].addBoth (self .check_context , None )
134
120
135
- yield make_deferred_yieldable (res_deferreds [0 ])
121
+ await make_deferred_yieldable (res_deferreds [0 ])
136
122
137
- # let verify_json_objects_for_server finish its work before we kill the
138
- # logcontext
139
- yield self .clock .sleep (0 )
123
+ d0 = ensureDeferred (first_lookup ())
140
124
141
- d0 = first_lookup ()
142
-
143
- # wait a tick for it to send the request to the perspectives server
144
- # (it first tries the datastore)
145
- self .pump ()
146
- self .http_client .post_json .assert_called_once ()
125
+ mock_fetcher .get_keys .assert_called_once ()
147
126
148
127
# a second request for a server with outstanding requests
149
128
# should block rather than start a second call
150
- @defer .inlineCallbacks
151
- def second_lookup ():
152
- with LoggingContext ("12" ) as context_12 :
153
- context_12 .request = "12"
154
- self .http_client .post_json .reset_mock ()
155
- self .http_client .post_json .return_value = defer .Deferred ()
129
+
130
+ async def second_lookup_fetch (keys_to_fetch ):
131
+ self .assertEquals (current_context ().request , "context_12" )
132
+ return {
133
+ "server10" : {
134
+ get_key_id (key1 ): FetchKeyResult (get_verify_key (key1 ), 100 )
135
+ }
136
+ }
137
+
138
+ mock_fetcher .get_keys .reset_mock ()
139
+ mock_fetcher .get_keys .side_effect = second_lookup_fetch
140
+ second_lookup_state = [0 ]
141
+
142
+ async def second_lookup ():
143
+ with LoggingContext ("context_12" ) as context_12 :
144
+ context_12 .request = "context_12"
156
145
157
146
res_deferreds_2 = kr .verify_json_objects_for_server (
158
147
[("server10" , json1 , 0 , "test" )]
159
148
)
160
149
res_deferreds_2 [0 ].addBoth (self .check_context , None )
161
- yield make_deferred_yieldable (res_deferreds_2 [0 ])
150
+ second_lookup_state [0 ] = 1
151
+ await make_deferred_yieldable (res_deferreds_2 [0 ])
152
+ second_lookup_state [0 ] = 2
162
153
163
- # let verify_json_objects_for_server finish its work before we kill the
164
- # logcontext
165
- yield self .clock .sleep (0 )
166
-
167
- d2 = second_lookup ()
154
+ d2 = ensureDeferred (second_lookup ())
168
155
169
156
self .pump ()
170
- self .http_client .post_json .assert_not_called ()
157
+ # the second request should be pending, but the fetcher should not yet have been
158
+ # called
159
+ self .assertEqual (second_lookup_state [0 ], 1 )
160
+ mock_fetcher .get_keys .assert_not_called ()
171
161
172
162
# complete the first request
173
- persp_deferred .callback (persp_resp )
163
+ first_lookup_deferred .callback (None )
164
+
165
+ # and now both verifications should succeed.
174
166
self .get_success (d0 )
175
167
self .get_success (d2 )
176
168
0 commit comments