|
21 | 21 | import typing |
22 | 22 | import warnings |
23 | 23 | import httpx |
24 | | -from typing import List |
25 | 24 |
|
26 | 25 | from .auth_builtins import _ProductionEnv, _OIDC_AUTH_CLIENT_CONFIG__USER_SKEL, _OIDC_AUTH_CLIENT_CONFIG__M2M_SKEL |
27 | 26 | import planet_auth |
@@ -132,7 +131,7 @@ def from_profile( |
132 | 131 | def from_oauth_user_auth_code( |
133 | 132 | client_id: str, |
134 | 133 | callback_url: str, |
135 | | - requested_scopes: typing.Optional[List[str]] = None, |
| 134 | + requested_scopes: typing.Optional[typing.List[str]] = None, |
136 | 135 | save_state_to_storage: bool = True, |
137 | 136 | profile_name: typing.Optional[str] = None, |
138 | 137 | storage_provider: typing.Optional[ |
@@ -193,7 +192,7 @@ def from_oauth_user_auth_code( |
193 | 192 | @staticmethod |
194 | 193 | def from_oauth_user_device_code( |
195 | 194 | client_id: str, |
196 | | - requested_scopes: typing.Optional[List[str]] = None, |
| 195 | + requested_scopes: typing.Optional[typing.List[str]] = None, |
197 | 196 | save_state_to_storage: bool = True, |
198 | 197 | profile_name: typing.Optional[str] = None, |
199 | 198 | storage_provider: typing.Optional[ |
@@ -255,7 +254,7 @@ def from_oauth_user_device_code( |
255 | 254 | def from_oauth_m2m( |
256 | 255 | client_id: str, |
257 | 256 | client_secret: str, |
258 | | - requested_scopes: typing.Optional[List[str]] = None, |
| 257 | + requested_scopes: typing.Optional[typing.List[str]] = None, |
259 | 258 | save_state_to_storage: bool = True, |
260 | 259 | profile_name: typing.Optional[str] = None, |
261 | 260 | storage_provider: typing.Optional[ |
@@ -456,7 +455,66 @@ def is_initialized(self) -> bool: |
456 | 455 | user based sessions, this means that a login has been performed |
457 | 456 | or saved login session data has been located. For M2M and API Key |
458 | 457 | sessions, this should be true if keys or secrets have been |
459 | | - properly configured. |
| 458 | + properly configured. The network will not be probed, and the user |
| 459 | + will not be prompted by this method. |
| 460 | +
|
| 461 | + Expired sessions or invalid credentials will not be detected. |
| 462 | + See `ensure_initialized()` for a method that will check the validity |
| 463 | + of sessions. |
| 464 | + """ |
| 465 | + |
| 466 | + @abc.abstractmethod |
| 467 | + def ensure_initialized( |
| 468 | + self, |
| 469 | + allow_open_browser: typing.Optional[bool] = False, |
| 470 | + allow_tty_prompt: typing.Optional[bool] = False, |
| 471 | + ) -> None: |
| 472 | + """ |
| 473 | + Do everything necessary to ensure the auth context is ready for use, |
| 474 | + while still biasing towards just-in-time operations and not making |
| 475 | + unnecessary network requests or prompts for user interaction. |
| 476 | +
|
| 477 | + This can be more complex than it sounds given the variations in |
| 478 | + possible session state. Clients may be initialized with active |
| 479 | + sessions, initialized with stale but still valid sessions, |
| 480 | + initialized with invalid or expired sessions, or completely |
| 481 | + uninitialized. The process taken to ensure client readiness with |
| 482 | + as little user disruption as possible is as follows: |
| 483 | +
|
| 484 | + 1. If the client has been logged in and has a non-expired |
| 485 | + session, the client will be considered ready without prompting |
| 486 | + the user or probing the network. This will not require user |
| 487 | + interaction. |
| 488 | + 2. If the client has not been logged in and is an M2M client, |
| 489 | + the client will be considered ready without prompting |
| 490 | + the user or probing the network. This will not require |
| 491 | + user interaction. Login will be delayed until it is required. |
| 492 | + 3. If the client has been logged in and has an expired access token, |
| 493 | + the network will be probed to attempt a refresh of the session. |
| 494 | + This should not require user interaction. If refresh fails, |
| 495 | + the user will be prompted to perform a fresh login, requiring |
| 496 | + user interaction. |
| 497 | + 4. If the client has never been logged in and is a user interactive |
| 498 | + client (verses an M2M client), a user interactive login will be |
| 499 | + initiated. |
| 500 | +
|
| 501 | + There still may be conditions where we believe we are |
| 502 | + ready, but requests will still ultimately fail. Saved secrets for M2M |
| 503 | + clients could be wrong, or the user could be denied by API access |
| 504 | + rules that are independent of session authentication. |
| 505 | +
|
| 506 | + When a user interactive login is required, the client must specify |
| 507 | + whether a local web browser may be opened and/or whether the TTY |
| 508 | + may be used to prompt the user. What is appropriate will depend |
| 509 | + on the nature of the application using the Planet SDK. |
| 510 | +
|
| 511 | + If the auth context cannot be made ready, an exception will be raised. |
| 512 | +
|
| 513 | + Parameters: |
| 514 | + allow_open_browser: specify whether login is permitted to open |
| 515 | + a local browser window. |
| 516 | + allow_tty_prompt: specify whether login is permitted to request |
| 517 | + input from the terminal. |
460 | 518 | """ |
461 | 519 |
|
462 | 520 |
|
@@ -496,5 +554,15 @@ def device_user_login_complete(self, login_initialization_info: dict): |
496 | 554 | def is_initialized(self) -> bool: |
497 | 555 | return self._plauth.request_authenticator_is_ready() |
498 | 556 |
|
| 557 | + def ensure_initialized( |
| 558 | + self, |
| 559 | + allow_open_browser: typing.Optional[bool] = False, |
| 560 | + allow_tty_prompt: typing.Optional[bool] = False, |
| 561 | + ) -> None: |
| 562 | + return self._plauth.ensure_request_authenticator_is_ready( |
| 563 | + allow_open_browser=allow_open_browser, |
| 564 | + allow_tty_prompt=allow_tty_prompt, |
| 565 | + ) |
| 566 | + |
499 | 567 |
|
500 | 568 | AuthType = Auth |
0 commit comments