@@ -95,17 +95,22 @@ def do_GET(self):
9595 if qs .get ('code' ) or qs .get ("error" ): # So, it is an auth response
9696 auth_response = _qs2kv (qs )
9797 logger .debug ("Got auth response: %s" , auth_response )
98- template = ( self .server .success_template
99- if "code" in qs else self . server . error_template )
100- if _is_html ( template . template ):
101- safe_data = _escape ( auth_response )
98+ if self . server . auth_state and self .server .auth_state != auth_response . get ( "state" ):
99+ # OAuth2 successful and error responses contain state when it was used
100+ # https://www.rfc-editor.org/rfc/rfc6749#section-4.2.2.1
101+ self . _send_full_response ( "State mismatch" ) # Possibly an attack
102102 else :
103- safe_data = auth_response
104- self ._send_full_response (template .safe_substitute (** safe_data ))
105- self .server .auth_response = auth_response # Set it now, after the response is likely sent
106- # NOTE: Don't do self.server.shutdown() here. It'll halt the server.
103+ template = (self .server .success_template
104+ if "code" in qs else self .server .error_template )
105+ if _is_html (template .template ):
106+ safe_data = _escape (auth_response ) # Foiling an XSS attack
107+ else :
108+ safe_data = auth_response
109+ self ._send_full_response (template .safe_substitute (** safe_data ))
110+ self .server .auth_response = auth_response # Set it now, after the response is likely sent
107111 else :
108112 self ._send_full_response (self .server .welcome_page )
113+ # NOTE: Don't do self.server.shutdown() here. It'll halt the server.
109114
110115 def _send_full_response (self , body , is_ok = True ):
111116 self .send_response (200 if is_ok else 400 )
@@ -295,16 +300,14 @@ def _get_auth_response(self, result, auth_uri=None, timeout=None, state=None,
295300
296301 self ._server .timeout = timeout # Otherwise its handle_timeout() won't work
297302 self ._server .auth_response = {} # Shared with _AuthCodeHandler
303+ self ._server .auth_state = state # So handler will check it before sending response
298304 while not self ._closing : # Otherwise, the handle_request() attempt
299305 # would yield noisy ValueError trace
300306 # Derived from
301307 # https://docs.python.org/2/library/basehttpserver.html#more-examples
302308 self ._server .handle_request ()
303309 if self ._server .auth_response :
304- if state and state != self ._server .auth_response .get ("state" ):
305- logger .debug ("State mismatch. Ignoring this noise." )
306- else :
307- break
310+ break
308311 result .update (self ._server .auth_response ) # Return via writable result param
309312
310313 def close (self ):
0 commit comments