Manages the local web server that will be used to retrieve the authorization code from the OAuth callback
| 221 | |
| 222 | |
| 223 | class AuthCodeFetcher: |
| 224 | """Manages the local web server that will be used |
| 225 | to retrieve the authorization code from the OAuth callback |
| 226 | """ |
| 227 | |
| 228 | # How many seconds handle_request should wait for an incoming request |
| 229 | _REQUEST_TIMEOUT = 10 |
| 230 | # How long we wait overall for the callback |
| 231 | _OVERALL_TIMEOUT = 60 * 10 |
| 232 | |
| 233 | def __init__(self): |
| 234 | self._auth_code = None |
| 235 | self._state = None |
| 236 | self._is_done = False |
| 237 | |
| 238 | # We do this so that the request handler can have a reference to this |
| 239 | # AuthCodeFetcher so that it can pass back the state and auth code |
| 240 | try: |
| 241 | handler = partial(OAuthCallbackHandler, self) |
| 242 | self.http_server = HTTPServer(('', 0), handler) |
| 243 | self.http_server.timeout = self._REQUEST_TIMEOUT |
| 244 | except OSError as e: |
| 245 | raise AuthCodeFetcherError(error_msg=e) |
| 246 | |
| 247 | def redirect_uri_without_port(self): |
| 248 | return 'http://127.0.0.1/oauth/callback' |
| 249 | |
| 250 | def redirect_uri_with_port(self): |
| 251 | return ( |
| 252 | f'http://127.0.0.1:{self.http_server.server_port}/oauth/callback' |
| 253 | ) |
| 254 | |
| 255 | def get_auth_code_and_state(self): |
| 256 | """Blocks until the expected redirect request with either the |
| 257 | authorization code/state or and error is handled |
| 258 | """ |
| 259 | LOG.debug(f'Waiting for auth code at {self.redirect_uri_with_port()}') |
| 260 | start = time.time() |
| 261 | while ( |
| 262 | not self._is_done and time.time() < start + self._OVERALL_TIMEOUT |
| 263 | ): |
| 264 | self.http_server.handle_request() |
| 265 | self.http_server.server_close() |
| 266 | |
| 267 | if not self._is_done: |
| 268 | raise PendingAuthorizationExpiredError |
| 269 | |
| 270 | return self._auth_code, self._state |
| 271 | |
| 272 | def set_auth_code_and_state(self, auth_code, state): |
| 273 | self._auth_code = auth_code |
| 274 | self._state = state |
| 275 | self._is_done = True |
| 276 | |
| 277 | |
| 278 | class OAuthCallbackHandler(BaseHTTPRequestHandler): |
no outgoing calls