33from datetime import datetime , timedelta , timezone
44from getpass import getpass
55from threading import Lock
6- from typing import TYPE_CHECKING , Any , Dict , Optional , Type
6+ from typing import TYPE_CHECKING , Any , Dict , Optional , Type , overload
77
88try :
99 import boto3
@@ -227,6 +227,18 @@ def _request_access_token(self) -> AccessToken:
227227 return AccessToken (type = "user" , ** resp .json ())
228228
229229
230+ @overload
231+ def prompt_for_credentials (
232+ provider_type : Type [UserCredentialsProvider ],
233+ ) -> UserCredentialsProvider : ...
234+
235+
236+ @overload
237+ def prompt_for_credentials (
238+ provider_type : Type [ApiClientCredentialsProvider ],
239+ ) -> ApiClientCredentialsProvider : ...
240+
241+
230242def prompt_for_credentials (provider_type : Type [CredentialsProvider ]) -> CredentialsProvider :
231243 """Prompts the user for credentials based on the given provider type.
232244
@@ -311,30 +323,58 @@ def load_from_aws_secrets_manager(
311323 return provider_type (** credentials )
312324
313325
326+ @overload
327+ def load_from_keychain (
328+ provider_type : Type [UserCredentialsProvider ],
329+ server : str ,
330+ * ,
331+ username : str ,
332+ client_id : None = None ,
333+ ) -> UserCredentialsProvider : ...
334+
335+
336+ @overload
314337def load_from_keychain (
315- provider_type : Type [CredentialsProvider ], server : str
338+ provider_type : Type [ApiClientCredentialsProvider ],
339+ server : str ,
340+ * ,
341+ client_id : str ,
342+ username : None = None ,
343+ ) -> ApiClientCredentialsProvider : ...
344+
345+
346+ def load_from_keychain (
347+ provider_type : Type [CredentialsProvider ],
348+ server : str ,
349+ client_id : Optional [str ] = None ,
350+ username : Optional [str ] = None ,
316351) -> CredentialsProvider :
317352 """Load credentials from the macOS login keychain and return an instance of the
318353 specified credentials provider.
319354
355+ .. important::
356+
357+ This credentials provider requires the ``macOS`` extra dependency.
358+
320359 The Jamf Pro API password or client credentials are stored in the keychain with
321360 the ``service_name`` set to the Jamf Pro server name.
322361
323362 Supports:
324- - ``UserCredentialsProvider``: retrieves password using provided username
325- - ``ApiClientCredentialsProvider``: retrieves Client ID and Client Secret using usernames of
326- "CLIENT_ID" and "CLIENT_SECRET"
327-
328- .. important::
329-
330- This credentials provider requires the ``macOS`` extra dependency.
363+ - ``UserCredentialsProvider``: Retrieves a password using the provided ``username``.
364+ - ``ApiClientCredentialsProvider``: Retrieves the API client secret using the provided ``client_id``.
331365
332366 :param provider_type: The credentials provider class to instantiate
333367 :type provider_type: Type[CredentialsProvider]
334368
335369 :param server: The Jamf Pro server name.
336370 :type server: str
337371
372+ :param client_id: The client ID used for ``ApiClientCredentialsProvider``. Required if ``provider_type`` is that provider.
373+ :type client_id: Optional[str]
374+
375+ :param username: The username used for ``UserCredentialsProvider``. Required if ``provider_type`` is that provider.
376+ :type username: Optional[str]
377+
338378 :return: An instantiated credentials provider using the keychain values.
339379 :rtype: CredentialsProvider
340380 """
@@ -347,20 +387,22 @@ def load_from_keychain(
347387 server = f"https://{ server } "
348388
349389 if issubclass (provider_type , UserCredentialsProvider ):
350- username = input ("Jamf Pro Username: " )
351- password = keyring .get_password (service_name = server , username = username )
352- if password is None :
353- raise CredentialsError (
354- f"Password not found for server { server } and username { username } "
390+ if username is None :
391+ raise ValueError (
392+ "Username argument is required to create UserCredentialsProvider object."
355393 )
356- return provider_type ( username , password )
394+ identity = username
357395 elif issubclass (provider_type , ApiClientCredentialsProvider ):
358- client_id = keyring .get_password (service_name = server , username = "CLIENT_ID" )
359- client_secret = keyring .get_password (service_name = server , username = "CLIENT_SECRET" )
360- if not client_id or not client_secret :
361- raise CredentialsError (
362- f"API Credentials were not found for server { server } . Please verify they are in the correct format."
396+ if client_id is None :
397+ raise ValueError (
398+ "API Client ID is required to instantiate ApiClientCredentialsProvider."
363399 )
364- return provider_type ( client_id , client_secret )
400+ identity = client_id
365401 else :
366402 raise TypeError (f"Unsupported credentials provider: { provider_type } " )
403+
404+ password = keyring .get_password (service_name = server , username = identity )
405+ if password is None :
406+ raise CredentialsError (f"Password not found for server { server } and username { identity } " )
407+
408+ return provider_type (identity , password )
0 commit comments