1212
1313from saml2 .entity import Entity
1414
15- import saml2 .attributemaps as attributemaps
16-
1715from saml2 .mdstore import destinations
1816from saml2 .profile import paos , ecp
1917from saml2 .saml import NAMEID_FORMAT_TRANSIENT
2422from saml2 .samlp import AuthnRequest
2523from saml2 .samlp import Extensions
2624from saml2 .extension import sp_type
27- from saml2 .extension import requested_attributes
25+ from saml2 .extension .requested_attributes import RequestedAttribute
26+ from saml2 .extension .requested_attributes import RequestedAttributes
2827
2928import saml2
3029from saml2 .soap import make_soap_enveloped_saml_thingy
@@ -235,7 +234,7 @@ def create_authn_request(self, destination, vorg="", scoping=None,
235234 service_url_binding = None , message_id = 0 ,
236235 consent = None , extensions = None , sign = None ,
237236 allow_create = None , sign_prepare = False , sign_alg = None ,
238- digest_alg = None , ** kwargs ):
237+ digest_alg = None , requested_attributes = None , ** kwargs ):
239238 """ Creates an authentication request.
240239
241240 :param destination: Where the request should be sent.
@@ -253,6 +252,11 @@ def create_authn_request(self, destination, vorg="", scoping=None,
253252 :param allow_create: If the identity provider is allowed, in the course
254253 of fulfilling the request, to create a new identifier to represent
255254 the principal.
255+ :param requested_attributes: A list of dicts which define attributes to
256+ be used as eIDAS Requested Attributes for this request. If not
257+ defined the configuration option requested_attributes will be used,
258+ if defined. The format is the same as the requested_attributes
259+ configuration option.
256260 :param kwargs: Extra key word arguments
257261 :return: either a tuple of request ID and <samlp:AuthnRequest> instance
258262 or a tuple of request ID and str when sign is set to True
@@ -379,58 +383,62 @@ def create_authn_request(self, destination, vorg="", scoping=None,
379383 item = sp_type .SPType (text = conf_sp_type )
380384 extensions .add_extension_element (item )
381385
382- requested_attrs = self .config .getattr ('requested_attributes' , 'sp' )
383- if requested_attrs :
384- if not extensions :
385- extensions = Extensions ()
386+ requested_attrs = (
387+ requested_attributes
388+ or self .config .getattr ('requested_attributes' , 'sp' )
389+ or []
390+ )
391+
392+ if not extensions :
393+ extensions = Extensions ()
394+
395+ items = []
396+ for attr in requested_attrs :
397+ friendly_name = attr .get ('friendly_name' )
398+ name = attr .get ('name' )
399+ name_format = attr .get ('name_format' )
400+ is_required = str (attr .get ('required' , False )).lower ()
401+
402+ if not name and not friendly_name :
403+ raise ValueError (
404+ "Missing required attribute: '{}' or '{}'" .format (
405+ 'name' , 'friendly_name'
406+ )
407+ )
408+
409+ if not name :
410+ for converter in self .config .attribute_converters :
411+ try :
412+ name = converter ._to [friendly_name .lower ()]
413+ except KeyError :
414+ continue
415+ else :
416+ if not name_format :
417+ name_format = converter .name_format
418+ break
386419
387- attributemapsmods = []
388- for modname in attributemaps .__all__ :
389- attributemapsmods .append (getattr (attributemaps , modname ))
390-
391- items = []
392- for attr in requested_attrs :
393- friendly_name = attr .get ('friendly_name' )
394- name = attr .get ('name' )
395- name_format = attr .get ('name_format' )
396- is_required = str (attr .get ('required' , False )).lower ()
397-
398- if not name and not friendly_name :
399- raise ValueError (
400- "Missing required attribute: '{}' or '{}'" .format (
401- 'name' , 'friendly_name' ))
402-
403- if not name :
404- for mod in attributemapsmods :
405- try :
406- name = mod .MAP ['to' ][friendly_name ]
407- except KeyError :
408- continue
409- else :
410- if not name_format :
411- name_format = mod .MAP ['identifier' ]
412- break
413-
414- if not friendly_name :
415- for mod in attributemapsmods :
416- try :
417- friendly_name = mod .MAP ['fro' ][name ]
418- except KeyError :
419- continue
420- else :
421- if not name_format :
422- name_format = mod .MAP ['identifier' ]
423- break
420+ if not friendly_name :
421+ for converter in self .config .attribute_converters :
422+ try :
423+ friendly_name = converter ._fro [name .lower ()]
424+ except KeyError :
425+ continue
426+ else :
427+ if not name_format :
428+ name_format = converter .name_format
429+ break
424430
425- items .append (requested_attributes .RequestedAttribute (
431+ items .append (
432+ RequestedAttribute (
426433 is_required = is_required ,
427434 name_format = name_format ,
428435 friendly_name = friendly_name ,
429- name = name ))
436+ name = name ,
437+ )
438+ )
430439
431- item = requested_attributes .RequestedAttributes (
432- extension_elements = items )
433- extensions .add_extension_element (item )
440+ item = RequestedAttributes (extension_elements = items )
441+ extensions .add_extension_element (item )
434442
435443 force_authn = str (
436444 kwargs .pop ("force_authn" , None )
@@ -450,8 +458,7 @@ def create_authn_request(self, destination, vorg="", scoping=None,
450458 if sign is None :
451459 sign = self .authn_requests_signed
452460
453- if (sign and self .sec .cert_handler .generate_cert ()) or \
454- client_crt is not None :
461+ if (sign and self .sec .cert_handler .generate_cert ()) or client_crt is not None :
455462 with self .lock :
456463 self .sec .cert_handler .update_cert (True , client_crt )
457464 if client_crt is not None :
0 commit comments