1
+ import collections
2
+
1
3
import six
2
4
3
5
from gssapi .raw import names as rname
4
6
from gssapi .raw import NameType
7
+ from gssapi .raw import named_tuples as tuples
5
8
from gssapi import _utils
6
9
10
+ rname_rfc6680 = _utils .import_gssapi_extension ('rfc6680' )
11
+
7
12
8
13
class Name (rname .Name ):
9
14
"""GSSAPI Name
@@ -20,9 +25,31 @@ class Name(rname.Name):
20
25
text of the name.
21
26
"""
22
27
23
- __slots__ = ()
28
+ __slots__ = ('_attr_obj' )
29
+
30
+ def __new__ (cls , base = None , name_type = None , token = None ,
31
+ composite = False ):
32
+ if token is not None :
33
+ if composite :
34
+ if rname_rfc6680 is None :
35
+ raise NotImplementedError (
36
+ "Your GSSAPI implementation does not support RFC 6680 "
37
+ "(the GSSAPI naming extensions)" )
38
+
39
+ base_name = rname .import_name (token , NameType .composite_export )
40
+ else :
41
+ base_name = rname .import_name (token , NameType .export )
42
+ elif isinstance (base , rname .Name ):
43
+ base_name = base
44
+ else :
45
+ if isinstance (base , six .text_type ):
46
+ base = base .encode (_utils ._get_encoding ())
47
+
48
+ base_name = rname .import_name (base , name_type )
24
49
25
- def __new__ (cls , base = None , name_type = None , token = None ):
50
+ return super (Name , cls ).__new__ (cls , base_name )
51
+
52
+ def __init__ (self , base = None , name_type = None , token = None , composite = False ):
26
53
"""Create or import a GSSAPI name
27
54
28
55
The constructor either creates or imports a GSSAPI name.
@@ -32,7 +59,8 @@ def __new__(cls, base=None, name_type=None, token=None):
32
59
high-level object.
33
60
34
61
If the `token` argument is used, the name will be imported using
35
- the token.
62
+ the token. If the token was exported as a composite token,
63
+ pass `composite=True`.
36
64
37
65
Otherwise, a new name will be created, using the `base` argument as
38
66
the string and the `name_type` argument to denote the name type.
@@ -43,17 +71,10 @@ def __new__(cls, base=None, name_type=None, token=None):
43
71
BadMechanismError
44
72
"""
45
73
46
- if token is not None :
47
- base_name = rname .import_name (token , NameType .export )
48
- elif isinstance (base , rname .Name ):
49
- base_name = base
74
+ if rname_rfc6680 is not None :
75
+ self ._attr_obj = _NameAttributeMapping (self )
50
76
else :
51
- if isinstance (base , six .text_type ):
52
- base = base .encode (_utils ._get_encoding ())
53
-
54
- base_name = rname .import_name (base , name_type )
55
-
56
- return super (Name , cls ).__new__ (cls , base_name )
77
+ self ._attr_obj = None
57
78
58
79
def __str__ (self ):
59
80
if issubclass (str , six .text_type ):
@@ -71,6 +92,30 @@ def __bytes__(self):
71
92
# Python 3 -- someone asked for bytes
72
93
return rname .display_name (self , name_type = False ).name
73
94
95
+ def display_as (self , name_type ):
96
+ """
97
+ Display the current name as the given name type.
98
+
99
+ This method attempts to display the current Name using
100
+ the syntax of the given NameType, if possible.
101
+
102
+ Args:
103
+ name_type (OID): the NameType to use to display the given name
104
+
105
+ Returns:
106
+ str: the displayed name
107
+
108
+ Raises:
109
+ OperationUnavailableError
110
+ """
111
+
112
+ if rname_rfc6680 is None :
113
+ raise NotImplementedError ("Your GSSAPI implementation does not "
114
+ "support RFC 6680 (the GSSAPI naming "
115
+ "extensions)" )
116
+ return rname_rfc6680 .display_name_ext (self , name_type ).encode (
117
+ _utils .get_encoding ())
118
+
74
119
@property
75
120
def name_type (self ):
76
121
"""Get the name type of this name"""
@@ -92,7 +137,7 @@ def __repr__(self):
92
137
return "Name({name}, {name_type})" .format (name = disp_res .name ,
93
138
name_type = disp_res .name_type )
94
139
95
- def export (self ):
140
+ def export (self , composite = False ):
96
141
"""Export the name
97
142
98
143
This method exports the name into a byte string which can then be
@@ -107,7 +152,15 @@ def export(self):
107
152
BadNameError
108
153
"""
109
154
110
- return rname .export_name (self )
155
+ if composite :
156
+ if rname_rfc6680 is None :
157
+ raise NotImplementedError ("Your GSSAPI implementation does "
158
+ "not support RFC 6680 (the GSSAPI "
159
+ "naming extensions)" )
160
+
161
+ return rname_rfc6680 .export_name_composite (self )
162
+ else :
163
+ return rname .export_name (self )
111
164
112
165
def canonicalize (self , mech ):
113
166
"""Canonicalize a name with respect to a mechanism
@@ -134,3 +187,111 @@ def __copy__(self):
134
187
135
188
def __deepcopy__ (self , memo ):
136
189
return type (self )(rname .duplicate_name (self ))
190
+
191
+ def _inquire (self , ** kwargs ):
192
+ """Inspect the name for information
193
+
194
+ This method inspects the name for information.
195
+
196
+ If no keyword arguments are passed, all available information
197
+ is returned. Otherwise, only the keyword arguments that
198
+ are passed and set to `True` are returned.
199
+
200
+ Args:
201
+ mech_name (bool): get whether this is a mechanism name,
202
+ and, if so, the associated mechanism
203
+ attrs (bool): get the attributes names for this name
204
+
205
+ Returns:
206
+ InquireNameResult: the results of the inquiry, with unused
207
+ fields set to None
208
+
209
+ Raises:
210
+ GSSError
211
+ """
212
+
213
+ if rname_rfc6680 is None :
214
+ raise NotImplementedError ("Your GSSAPI implementation does not "
215
+ "support RFC 6680 (the GSSAPI naming "
216
+ "extensions)" )
217
+
218
+ if not kwargs :
219
+ default_val = True
220
+ else :
221
+ default_val = False
222
+
223
+ attrs = kwargs .get ('attrs' , default_val )
224
+ mech_name = kwargs .get ('mech_name' , default_val )
225
+
226
+ return rname_rfc6680 .inquire_name (self , mech_name = mech_name ,
227
+ attrs = attrs )
228
+
229
+ @property
230
+ def is_mech_name (self ):
231
+ return self ._inquire (mech_name = True ).is_mech_name
232
+
233
+ @property
234
+ def mech (self ):
235
+ return self ._inquire (mech_name = True ).mech
236
+
237
+ @property
238
+ def attributes (self ):
239
+ if self ._attr_obj is None :
240
+ raise NotImplementedError ("Your GSSAPI implementation does not "
241
+ "support RFC 6680 (the GSSAPI naming "
242
+ "extensions)" )
243
+
244
+ return self ._attr_obj
245
+
246
+
247
+ class _NameAttributeMapping (collections .MutableMapping ):
248
+
249
+ """Provides dict-like access to RFC 6680 Name attributes."""
250
+ def __init__ (self , name ):
251
+ self ._name = name
252
+
253
+ def __getitem__ (self , key ):
254
+ if isinstance (key , six .text_type ):
255
+ key = key .encode (_utils ._get_encoding ())
256
+
257
+ res = rname_rfc6680 .get_name_attribute (self ._name , key )
258
+ return tuples .GetNameAttributeResult (frozenset (res .values ),
259
+ frozenset (res .display_values ),
260
+ res .authenticated ,
261
+ res .complete )
262
+
263
+ def __setitem__ (self , key , value ):
264
+ if isinstance (key , six .text_type ):
265
+ key = key .encode (_utils ._get_encoding ())
266
+
267
+ rname_rfc6680 .delete_name_attribute (self ._name , key )
268
+
269
+ if isinstance (value , tuples .GetNameAttributeResult ):
270
+ complete = value .complete
271
+ value = value .values
272
+ elif isinstance (value , tuple ) and len (value ) == 2 :
273
+ complete = value [1 ]
274
+ value = value [0 ]
275
+ else :
276
+ complete = False
277
+
278
+ if (isinstance (value , (six .string_types , bytes )) or
279
+ not isinstance (value , collections .Iterable )):
280
+ # NB(directxman12): this allows us to easily assign a single
281
+ # value, since that's a common case
282
+ value = [value ]
283
+
284
+ rname_rfc6680 .set_name_attribute (self ._name , key , value ,
285
+ complete = complete )
286
+
287
+ def __delitem__ (self , key ):
288
+ if isinstance (key , six .text_type ):
289
+ key = key .encode (_utils ._get_encoding ())
290
+
291
+ rname_rfc6680 .delete_name_attribute (self ._name , key )
292
+
293
+ def __iter__ (self ):
294
+ return iter (self ._name ._inquire (attrs = True ).attrs )
295
+
296
+ def __len__ (self ):
297
+ return len (self ._name ._inquire (attrs = True ).attrs )
0 commit comments