Source code for gssapi.creds

import typing as t

from gssapi.raw import creds as rcreds
from gssapi.raw import named_tuples as tuples
from gssapi.raw import names as rnames
from gssapi.raw import oids as roids
from gssapi._utils import import_gssapi_extension, _encode_dict

from gssapi import names

rcred_imp_exp = import_gssapi_extension('cred_imp_exp')
rcred_s4u = import_gssapi_extension('s4u')
rcred_cred_store = import_gssapi_extension('cred_store')
rcred_rfc5588 = import_gssapi_extension('rfc5588')


[docs] 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. The constructor either acquires or imports a set of GSSAPI credentials. If the `base` argument is used, an existing :class:`~gssapi.raw.creds.Creds` object from the low-level API is converted into a high-level object. If the `token` argument is used, the credentials are imported using the token, if the credentials import-export extension is supported (:requires-ext:`cred_imp_exp`). Otherwise, the credentials are acquired as per the :meth:`acquire` method. Raises: ~gssapi.exceptions.BadMechanismError ~gssapi.exceptions.BadNameTypeError ~gssapi.exceptions.BadNameError ~gssapi.exceptions.ExpiredCredentialsError ~gssapi.exceptions.MissingCredentialsError """ __slots__ = () def __new__( cls, base: t.Optional[rcreds.Creds] = None, token: t.Optional[bytes] = None, name: t.Optional[rnames.Name] = None, lifetime: t.Optional[int] = None, mechs: t.Optional[t.Iterable[roids.OID]] = None, usage: str = 'both', store: t.Optional[ t.Dict[t.Union[bytes, str], t.Union[bytes, str]] ] = None, ) -> "Credentials": # TODO(directxman12): this is missing support for password # (non-RFC method) if base is not None: base_creds = base elif token is not None: if rcred_imp_exp is None: raise NotImplementedError("Your GSSAPI implementation does " "not have support for importing and " "exporting creditials") base_creds = rcred_imp_exp.import_cred(token) else: res = cls.acquire(name, lifetime, mechs, usage, store=store) base_creds = res.creds return t.cast("Credentials", super(Credentials, cls).__new__(cls, base_creds)) @property def name(self) -> rnames.Name: """Get the name associated with these credentials""" return t.cast(rnames.Name, self.inquire(name=True, lifetime=False, usage=False, mechs=False).name) @property def lifetime(self) -> int: """Get the remaining lifetime of these credentials, in seconds""" return t.cast(int, self.inquire(name=False, lifetime=True, usage=False, mechs=False).lifetime) @property def mechs(self) -> t.Set[roids.OID]: """Get the mechanisms for these credentials""" return t.cast(t.Set[roids.OID], self.inquire(name=False, lifetime=False, usage=False, mechs=True).mechs) @property def usage(self) -> str: """Get the usage (initiate, accept, or both) of these credentials""" return t.cast(str, self.inquire(name=False, lifetime=False, usage=True, mechs=False).usage)
[docs] @classmethod def acquire( cls, name: t.Optional[rnames.Name] = None, lifetime: t.Optional[int] = None, mechs: t.Optional[t.Iterable[roids.OID]] = None, usage: str = 'both', store: t.Optional[ t.Dict[t.Union[bytes, str], t.Union[bytes, str]] ] = None, ) -> tuples.AcquireCredResult: """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: name (~gssapi.names.Name): the name associated with the credentials, or None for the default name lifetime (int): the desired lifetime of the credentials in seconds, or None for indefinite mechs (list): the desired :class:`MechType` OIDs to be used with the credentials, or None for the default set usage (str): the usage for the 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 (:requires-ext:`cred_store`) Returns: AcquireCredResult: the acquired credentials and information about them Raises: ~gssapi.exceptions.BadMechanismError ~gssapi.exceptions.BadNameTypeError ~gssapi.exceptions.BadNameError ~gssapi.exceptions.ExpiredCredentialsError ~gssapi.exceptions.MissingCredentialsError """ if store is None: res = rcreds.acquire_cred(name, lifetime, mechs, usage) else: if rcred_cred_store is None: raise NotImplementedError("Your GSSAPI implementation does " "not have support for manipulating " "credential stores") b_store = _encode_dict(store) res = rcred_cred_store.acquire_cred_from(b_store, name, lifetime, mechs, usage) return tuples.AcquireCredResult(cls(base=res.creds), res.mechs, res.lifetime)
[docs] def store( self, store: t.Optional[ t.Dict[t.Union[bytes, str], t.Union[bytes, str]] ] = None, usage: str = 'both', mech: t.Optional[roids.OID] = None, overwrite: bool = False, set_default: bool = False, ) -> tuples.StoreCredResult: """Store these credentials into 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. :requires-ext:`rfc5588` or :requires-ext:`cred_store` 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 (~gssapi.OID): the :class:`MechType` 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 Raises: ~gssapi.exceptions.GSSError ~gssapi.exceptions.ExpiredCredentialsError ~gssapi.exceptions.MissingCredentialsError ~gssapi.exceptions.OperationUnavailableError ~gssapi.exceptions.DuplicateCredentialsElementError """ if store is None: if rcred_rfc5588 is None: raise NotImplementedError("Your GSSAPI implementation does " "not have support for RFC 5588") return rcred_rfc5588.store_cred(self, usage, mech, overwrite, set_default) else: if rcred_cred_store is None: raise NotImplementedError("Your GSSAPI implementation does " "not have support for manipulating " "credential stores directly") b_store = _encode_dict(store) return rcred_cred_store.store_cred_into(b_store, self, usage, mech, overwrite, set_default)
[docs] def impersonate( self, name: t.Optional[rnames.Name] = None, lifetime: t.Optional[int] = None, mechs: t.Optional[t.Iterable[roids.OID]] = None, usage: str = 'initiate', ) -> "Credentials": """Impersonate a name using the current credentials This method acquires credentials by impersonating another name using the current credentials. :requires-ext:`s4u` Args: name (~gssapi.names.Name): the name to impersonate lifetime (int): the desired lifetime of the new credentials in seconds, or None for indefinite mechs (list): the desired :class:`MechType` OIDs 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 NotImplementedError("Your GSSAPI implementation does not " "have support for S4U") res = rcred_s4u.acquire_cred_impersonate_name(self, name, lifetime, mechs, usage) return type(self)(base=res.creds)
[docs] def inquire( self, name: bool = True, lifetime: bool = True, usage: bool = True, mechs: bool = True, ) -> tuples.InquireCredResult: """Inspect these credentials for information This method inspects these 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 Raises: ~gssapi.exceptions.MissingCredentialsError ~gssapi.exceptions.InvalidCredentialsError ~gssapi.exceptions.ExpiredCredentialsError """ res = rcreds.inquire_cred(self, name, lifetime, usage, mechs) if res.name is not None: res_name = names.Name(res.name) else: res_name = None return tuples.InquireCredResult(res_name, res.lifetime, res.usage, res.mechs)
[docs] def inquire_by_mech( self, mech: roids.OID, name: bool = True, init_lifetime: bool = True, accept_lifetime: bool = True, usage: bool = True, ) -> tuples.InquireCredByMechResult: """Inspect these credentials for per-mechanism information This method inspects these credentials for per-mechanism information about them. Args: mech (~gssapi.OID): the mechanism for which to retrieve the information name (bool): get the name associated with the credentials init_lifetime (bool): get the remaining initiate lifetime for the credentials in seconds accept_lifetime (bool): get the remaining accept lifetime for the credentials in seconds 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) if res.name is not None: res_name = names.Name(res.name) else: res_name = None return tuples.InquireCredByMechResult(res_name, res.init_lifetime, res.accept_lifetime, res.usage)
[docs] def add( self, name: rnames.Name, mech: roids.OID, usage: str = 'both', init_lifetime: t.Optional[int] = None, accept_lifetime: t.Optional[int] = None, impersonator: t.Optional[rcreds.Creds] = None, store: t.Optional[ t.Dict[t.Union[bytes, str], t.Union[bytes, str]] ] = None, ) -> "Credentials": """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 (:requires-ext:`s4u`). If the `store` argument is used, the credentials will be acquired from the given credential store (:requires-ext:`cred_store`). 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. Note that the `store` argument is not compatible with the `impersonator` argument. Args: name (~gssapi.names.Name): the name associated with the credentials mech (~gssapi.OID): the desired :class:`MechType` to be used with the credentials usage (str): the usage for the credentials -- either 'both', 'initiate', or 'accept' init_lifetime (int): the desired initiate lifetime of the credentials in seconds, or None for indefinite accept_lifetime (int): the desired accept lifetime of the credentials in seconds, or None for indefinite impersonator (Credentials): the credentials to use to impersonate the given name, or None to not acquire normally (:requires-ext:`s4u`) store (dict): the credential store information pointing to the credential store from which to acquire the credentials, or None for the default store (:requires-ext:`cred_store`) Returns: Credentials: the credentials set containing the current credentials and the newly acquired ones. Raises: ~gssapi.exceptions.BadMechanismError ~gssapi.exceptions.BadNameTypeError ~gssapi.exceptions.BadNameError ~gssapi.exceptions.DuplicateCredentialsElementError ~gssapi.exceptions.ExpiredCredentialsError ~gssapi.exceptions.MissingCredentialsError """ if store is not None and impersonator is not None: raise ValueError('You cannot use both the `impersonator` and ' '`store` arguments at the same time') if store is not None: if rcred_cred_store is None: raise NotImplementedError("Your GSSAPI implementation does " "not have support for manipulating " "credential stores") b_store = _encode_dict(store) res = rcred_cred_store.add_cred_from(b_store, self, name, mech, usage, init_lifetime, accept_lifetime) elif impersonator is not None: if rcred_s4u is None: raise NotImplementedError("Your GSSAPI implementation does " "not have support for S4U") res = rcred_s4u.add_cred_impersonate_name(self, impersonator, name, mech, usage, init_lifetime, accept_lifetime) else: res = rcreds.add_cred(self, name, mech, usage, init_lifetime, accept_lifetime) return Credentials(res.creds)
[docs] def export(self) -> bytes: """Export these credentials into 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. :requires-ext:`cred_imp_exp` Returns: bytes: the exported credentials in token form """ if rcred_imp_exp is None: raise NotImplementedError("Your GSSAPI implementation does not " "have support for importing and " "exporting creditials") return rcred_imp_exp.export_cred(self)
# pickle protocol support def __reduce__( self, ) -> t.Tuple[t.Type["Credentials"], t.Tuple[None, bytes]]: # the unpickle arguments to new are (base=None, token=self.export()) return (type(self), (None, self.export()))