/usr/lib/python3/dist-packages/gssapi/names.py is in python3-gssapi 1.1.3-2ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | import collections
import six
from gssapi.raw import names as rname
from gssapi.raw import NameType
from gssapi.raw import named_tuples as tuples
from gssapi import _utils
rname_rfc6680 = _utils.import_gssapi_extension('rfc6680')
rname_rfc6680_comp_oid = _utils.import_gssapi_extension('rfc6680_comp_oid')
class Name(rname.Name):
"""A GSSAPI Name
This class represents a GSSAPI name which may be used with
used with and/or returned by other GSSAPI methods.
It inherits from the low-level GSSAPI :class:`~gssapi.raw.names.Name`
class, and thus may used with both low-level and high-level API methods.
This class may be pickled and unpickled, as well as copied.
The :func:`str` and :func:`bytes` methods may be used to retrieve the
text of the name.
Note:
Name strings will be automatically converted to and from unicode
strings as appropriate. If a method is listed as returning a
:class:`str` object, it will return a unicode string.
The encoding used will be python-gssapi's current encoding, which
defaults to UTF-8.
"""
__slots__ = ('_attr_obj')
def __new__(cls, base=None, name_type=None, token=None,
composite=False):
if token is not None:
if composite:
if rname_rfc6680 is None:
raise NotImplementedError(
"Your GSSAPI implementation does not support RFC 6680 "
"(the GSSAPI naming extensions)")
if rname_rfc6680_comp_oid is not None:
base_name = rname.import_name(token,
NameType.composite_export)
displ_name = rname.display_name(base_name, name_type=True)
if displ_name.name_type == NameType.composite_export:
# NB(directxman12): there's a bug in MIT krb5 <= 1.13
# where GSS_C_NT_COMPOSITE_EXPORT doesn't trigger
# immediate import logic. However, we can just use
# the normal GSS_C_NT_EXPORT_NAME in this case.
base_name = rname.import_name(token, NameType.export)
else:
# NB(directxman12): some older versions of MIT krb5 don't
# have support for the GSS_C_NT_COMPOSITE_EXPORT, but do
# support composite tokens via GSS_C_NT_EXPORT_NAME.
base_name = rname.import_name(token, NameType.export)
else:
base_name = rname.import_name(token, NameType.export)
elif isinstance(base, rname.Name):
base_name = base
else:
if isinstance(base, six.text_type):
base = base.encode(_utils._get_encoding())
base_name = rname.import_name(base, name_type)
return super(Name, cls).__new__(cls, base_name)
def __init__(self, base=None, name_type=None, token=None, composite=False):
"""
The constructor can be used to "import" a name from a human readable
representation, or from a token, and can also be used to convert a
low-level :class:`gssapi.raw.names.Name` object into a high-level
object.
If a :class:`~gssapi.raw.names.Name` object from the low-level API
is passed as the `base` argument, it will be converted into a
high-level object.
If the `token` argument is used, the name will be imported using
the token. If the token was exported as a composite token,
pass `composite=True`.
Otherwise, a new name will be created, using the `base` argument as
the human-readable string and the `name_type` argument to denote the
name type.
Raises:
BadNameTypeError
BadNameError
BadMechanismError
"""
if rname_rfc6680 is not None:
self._attr_obj = _NameAttributeMapping(self)
else:
self._attr_obj = None
def __str__(self):
if issubclass(str, six.text_type):
# Python 3 -- we should return unicode
return bytes(self).decode(_utils._get_encoding())
else:
# Python 2 -- we should return a string
return self.__bytes__()
def __unicode__(self):
# Python 2 -- someone asked for unicode
return self.__bytes__().decode(_utils._get_encoding())
def __bytes__(self):
# Python 3 -- someone asked for bytes
return rname.display_name(self, name_type=False).name
def display_as(self, name_type):
"""
Display this name as the given name type.
This method attempts to display the current :class:`Name`
using the syntax of the given :class:`NameType`, if possible.
Warning:
In MIT krb5 versions below 1.13.3, this method can segfault if
the name was not *originally* created with a `name_type` that was
not ``None`` (even in cases when a ``name_type``
is later "added", such as via :meth:`canonicalize`).
**Do not use this method unless you are sure the above
conditions can never happen in your code.**
Warning:
In addition to the above warning, current versions of MIT krb5 do
not actually fully implement this method, and it may return
incorrect results in the case of canonicalized names.
:requires-ext:`rfc6680`
Args:
name_type (OID): the :class:`NameType` to use to display the given
name
Returns:
str: the displayed name
Raises:
OperationUnavailableError
"""
if rname_rfc6680 is None:
raise NotImplementedError("Your GSSAPI implementation does not "
"support RFC 6680 (the GSSAPI naming "
"extensions)")
return rname_rfc6680.display_name_ext(self, name_type).decode(
_utils._get_encoding())
@property
def name_type(self):
"""The :class:`NameType` of this name"""
return rname.display_name(self, name_type=True).name_type
def __eq__(self, other):
if not isinstance(other, rname.Name):
# maybe something else can compare this
# to other classes, but we certainly can't
return NotImplemented
else:
return rname.compare_name(self, other)
def __ne__(self, other):
return not self.__eq__(other)
def __repr__(self):
disp_res = rname.display_name(self, name_type=True)
return "Name({name}, {name_type})".format(name=disp_res.name,
name_type=disp_res.name_type)
def export(self, composite=False):
"""Export this name as a token.
This method exports the name into a byte string which can then be
imported by using the `token` argument of the constructor.
Args:
composite (bool): whether or not use to a composite token --
:requires-ext:`rfc6680`
Returns:
bytes: the exported name in token form
Raises:
MechanismNameRequiredError
BadNameTypeError
BadNameError
"""
if composite:
if rname_rfc6680 is None:
raise NotImplementedError("Your GSSAPI implementation does "
"not support RFC 6680 (the GSSAPI "
"naming extensions)")
return rname_rfc6680.export_name_composite(self)
else:
return rname.export_name(self)
def canonicalize(self, mech):
"""Canonicalize a name with respect to a mechanism.
This method returns a new :class:`Name` that is canonicalized according
to the given mechanism.
Args:
mech (OID): the :class:`MechType` to use
Returns:
Name: the canonicalized name
Raises:
BadMechanismError
BadNameTypeError
BadNameError
"""
return type(self)(rname.canonicalize_name(self, mech))
def __copy__(self):
return type(self)(rname.duplicate_name(self))
def __deepcopy__(self, memo):
return type(self)(rname.duplicate_name(self))
def _inquire(self, **kwargs):
"""Inspect this name for information.
This method inspects the name for information.
If no keyword arguments are passed, all available information
is returned. Otherwise, only the keyword arguments that
are passed and set to `True` are returned.
Args:
mech_name (bool): get whether this is a mechanism name,
and, if so, the associated mechanism
attrs (bool): get the attributes names for this name
Returns:
InquireNameResult: the results of the inquiry, with unused
fields set to None
Raises:
GSSError
"""
if rname_rfc6680 is None:
raise NotImplementedError("Your GSSAPI implementation does not "
"support RFC 6680 (the GSSAPI naming "
"extensions)")
if not kwargs:
default_val = True
else:
default_val = False
attrs = kwargs.get('attrs', default_val)
mech_name = kwargs.get('mech_name', default_val)
return rname_rfc6680.inquire_name(self, mech_name=mech_name,
attrs=attrs)
@property
def is_mech_name(self):
"""Whether or not this name is a mechanism name
(:requires-ext:`rfc6680`)
"""
return self._inquire(mech_name=True).is_mech_name
@property
def mech(self):
"""The mechanism associated with this name (:requires-ext:`rfc6680`)
"""
return self._inquire(mech_name=True).mech
@property
def attributes(self):
"""The attributes of this name (:requires-ext:`rfc6680`)
The attributes are presenting in the form of a
:class:`~collections.MutableMapping` (a dict-like object).
Retrieved values will always be in the form of :class:`frozensets`.
When assigning values, if iterables are used, they be considered to be
the set of values for the given attribute. If a non-iterable is used,
it will be considered a single value, and automatically wrapped in an
iterable.
Note:
String types (includes :class:`bytes`) are not considered to
be iterables in this case.
"""
if self._attr_obj is None:
raise NotImplementedError("Your GSSAPI implementation does not "
"support RFC 6680 (the GSSAPI naming "
"extensions)")
return self._attr_obj
class _NameAttributeMapping(collections.MutableMapping):
"""Provides dict-like access to RFC 6680 Name attributes."""
def __init__(self, name):
self._name = name
def __getitem__(self, key):
if isinstance(key, six.text_type):
key = key.encode(_utils._get_encoding())
res = rname_rfc6680.get_name_attribute(self._name, key)
return tuples.GetNameAttributeResult(frozenset(res.values),
frozenset(res.display_values),
res.authenticated,
res.complete)
def __setitem__(self, key, value):
if isinstance(key, six.text_type):
key = key.encode(_utils._get_encoding())
rname_rfc6680.delete_name_attribute(self._name, key)
if isinstance(value, tuples.GetNameAttributeResult):
complete = value.complete
value = value.values
elif isinstance(value, tuple) and len(value) == 2:
complete = value[1]
value = value[0]
else:
complete = False
if (isinstance(value, (six.string_types, bytes)) or
not isinstance(value, collections.Iterable)):
# NB(directxman12): this allows us to easily assign a single
# value, since that's a common case
value = [value]
rname_rfc6680.set_name_attribute(self._name, key, value,
complete=complete)
def __delitem__(self, key):
if isinstance(key, six.text_type):
key = key.encode(_utils._get_encoding())
rname_rfc6680.delete_name_attribute(self._name, key)
def __iter__(self):
return iter(self._name._inquire(attrs=True).attrs)
def __len__(self):
return len(self._name._inquire(attrs=True).attrs)
|