diff --git a/gssapi/creds.py b/gssapi/creds.py index 5677d228..23380c09 100644 --- a/gssapi/creds.py +++ b/gssapi/creds.py @@ -11,12 +11,41 @@ class Credentials(rcreds.Creds): + """GSSAPI Credentials + + This class represents a set of GSSAPI credentials which may + be used with and/or returned by other GSSAPI methods. + + It inherits from the low-level GSSAPI :class:`~gssapi.raw.creds.Creds` + class, and thus may used with both low-level and high-level API methods. + + If your implementation of GSSAPI supports the credentials import-export + extension, you may pickle and unpickle this object. + """ + __slots__ = () def __new__(cls, base=None, token=None, desired_name=None, lifetime=None, desired_mechs=None, usage='both', store=None): + """Acquire or import a set of credentials. + + The constructor either acquires or imports a set of GSSAPI + credentials. + + If the `base` argument is used, an existing + :class:`~gssapi.raw.creds.Cred` object from the low-level API is + converted into a high-level object. + + If the :python:`token` argument is used, the credentials + are imported using the token, if the credentials import-export + extension is supported. + + Otherwise, the credentials are acquired as per the + :meth:`acquire` method. + """ + # TODO(directxman12): this is missing support for password # (non-RFC method) if base is not None: @@ -37,27 +66,63 @@ def __new__(cls, base=None, token=None, @property def name(self): + """Get the name associated with the credentials""" return self.inquire(name=True, lifetime=False, usage=False, mechs=False).name @property def lifetime(self): + """Get the remaining lifetime of the credentials""" return self.inquire(name=False, lifetime=True, usage=False, mechs=False).lifetime @property def mechs(self): + """Get the mechanisms for the current credentials""" return self.inquire(name=False, lifetime=False, usage=False, mechs=True).mechs @property def usage(self): + """Get the usage (initiate, accept, or both) of the credentials""" return self.inquire(name=False, lifetime=False, usage=True, mechs=False).usage @classmethod def acquire(cls, desired_name=None, lifetime=None, desired_mechs=None, usage='both', store=None): + """Acquire GSSAPI credentials + + This method acquires credentials. If the `store` argument is + used, the credentials will be acquired from the given + credential store (if supported). Otherwise, the credentials are + acquired from the default store. + + The credential store information is a dictionary containing + mechanisms-specific keys and values pointing to a credential store + or stores. + + Using a non-default store requires support for the credentials store + extension. + + Args: + desired_name (Name): the name associated with the credentials, + or None for the default name + lifetime (int): the desired lifetime of the credentials, or None + for indefinite + desired_mechs (list): the desired mechanisms to be used with these + credentials, or None for the default set + usage (str): the usage for these credentials -- either 'both', + 'initiate', or 'accept' + store (dict): the credential store information pointing to the + credential store from which to acquire the credentials, + or None for the default store + + Returns: + AcquireCredResult: the acquired credentials and information about + them + """ + if store is None: res = rcreds.acquire_cred(desired_name, lifetime, desired_mechs, usage) @@ -78,6 +143,28 @@ def acquire(cls, desired_name=None, lifetime=None, def store(self, store=None, usage='both', mech=None, overwrite=False, set_default=False): + """Store credentials to the given store + + This method stores the current credentials into the specified + credentials store. If the default store is used, support for + RFC 5588 is required. Otherwise, support for the credentials + store extension is required. + + Args: + store (dict): the store into which to store the credentials, + or None for the default store. + usage (str): the usage to store the credentials with -- either + 'both', 'initiate', or 'accept' + mech (OID): the mechansim to associate with the stored credentials + overwrite (bool): whether or not to overwrite existing credentials + stored with the same name, etc + set_default (bool): whether or not to set these credentials as + the default credentials for the given store. + + Returns: + StoreCredResult: the results of the credential storing operation + """ + if store is None: if rcred_rfc5588 is None: raise AttributeError("Your GSSAPI implementation does not " @@ -98,6 +185,26 @@ def store(self, store=None, usage='both', mech=None, def impersonate(self, desired_name=None, lifetime=None, desired_mechs=None, usage='initiate'): + """Impersonate a name using the current credentials + + This method acquires credentials by impersonating another + name using the current credentials. This requires the + Services4User extension. + + Args: + desired_name (Name): the name to impersonate + lifetime (int): the desired lifetime of the new credentials, + or None for indefinite + desired_mechs (list): the desired mechanisms for the new + credentials + usage (str): the desired usage for the new credentials -- either + 'both', 'initiate', or 'accept'. Note that some mechanisms + may only support 'initiate'. + + Returns: + Credentials: the new credentials impersonating the given name + """ + if rcred_s4u is None: raise AttributeError("Your GSSAPI implementation does not " "have support for S4U") @@ -109,6 +216,21 @@ def impersonate(self, desired_name=None, lifetime=None, return type(self)(base=res.creds) def inquire(self, name=True, lifetime=True, usage=True, mechs=True): + """Inspect the credentials for information + + This method inspects the credentials for information about them. + + Args: + name (bool): get the name associated with the credentials + lifetime (bool): get the remaining lifetime for the credentials + usage (bool): get the usage for the credentials + mechs (bool): get the mechanisms associated with the credentials + + Returns: + InquireCredResult: the information about the credentials, + with None used when the corresponding argument was False + """ + res = rcreds.inquire_cred(self, name, lifetime, usage, mechs) if res.name is not None: @@ -121,6 +243,25 @@ def inquire(self, name=True, lifetime=True, usage=True, mechs=True): def inquire_by_mech(self, mech, name=True, init_lifetime=True, accept_lifetime=True, usage=True): + """Inspect the credentials for per-mechanism information + + This method inspects the credentials for per-mechanism information + about them + + Args: + mech (OID): the mechanism for which to retrive the information + name (bool): get the name associated with the credentials + init_lifetime (bool): get the remaining initiate lifetime for + the credentials + accept_lifetime (bool): get the remaining accept lifetime for + the credentials + usage (bool): get the usage for the credentials + + Returns: + InquireCredByMechResult: the information about the credentials, + with None used when the corresponding argument was False + """ + res = rcreds.inquire_cred_by_mech(self, mech, name, init_lifetime, accept_lifetime, usage) @@ -136,6 +277,37 @@ def inquire_by_mech(self, mech, name=True, init_lifetime=True, def add(self, desired_name, desired_mech, usage='both', init_lifetime=None, accept_lifetime=None, impersonator=None): + """Acquire more credentials to add to the current set + + This method works like :meth:`acquire`, except that it adds the + acquired credentials for a single mechanism to a copy of the current + set, instead of creating a new set for multiple mechanisms. + Unlike :meth:`acquire`, you cannot pass None desired name or + mechanism. + + If the `impersonator` argument is used, the credentials will + impersonate the given name using the impersonator credentials. + This requires the Services4User extension. + + Args: + desired_name (Name): the name associated with the + credentials + desired_mech (OID): the desired mechanism to be used with these + credentials + usage (str): the usage for these credentials -- either 'both', + 'initiate', or 'accept' + init_lifetime (int): the desired initiate lifetime of the + credentials, or None for indefinite + accept_lifetime (int): the desired accept lifetime of the + credentials, or None for indefinite + impersonator (Credentials): the credentials to use to impersonate + the given name, or None to not acquire normally + + Returns: + Credentials: the credentials set containing the current credentials + and the newly acquired ones. + """ + if impersonator is not None: if rcred_s4u is None: raise AttributeError("Your GSSAPI implementation does not " @@ -152,6 +324,17 @@ def add(self, desired_name, desired_mech, usage='both', return Credentials(res.creds) def export(self): + """Export the credentials to a token + + This method exports the current credentials to a token that can + then be imported by passing the `token` argument to the constructor. + + This is often used to pass credentials between processes. + + Returns: + bytes: the exported credentials in token form + """ + if rcred_imp_exp is None: raise AttributeError("Your GSSAPI implementation does not " "have support for importing and exporting "