Skip to content

Commit 61afe88

Browse files
author
Roland Hedberg
committed
add_header method and returning a byte string.
Fixed some PY3 problems service_per_endpoint method useful when setting up an entity instance.
1 parent 2ba6dd7 commit 61afe88

File tree

5 files changed

+87
-62
lines changed

5 files changed

+87
-62
lines changed

example/sp-wsgi/sp.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,7 @@ def dict_to_table(ava, lev=0, width=1):
6565
txt.append("<tr>\n")
6666
if isinstance(valarr, six.string_types):
6767
txt.append("<th>%s</th>\n" % str(prop))
68-
try:
69-
txt.append("<td>%s</td>\n" % valarr.encode("utf8"))
70-
except AttributeError:
71-
txt.append("<td>%s</td>\n" % valarr)
68+
txt.append("<td>%s</td>\n" % valarr)
7269
elif isinstance(valarr, list):
7370
i = 0
7471
n = len(valarr)
@@ -82,10 +79,7 @@ def dict_to_table(ava, lev=0, width=1):
8279
txt.extend(dict_to_table(val, lev + 1, width - 1))
8380
txt.append("</td>\n")
8481
else:
85-
try:
86-
txt.append("<td>%s</td>\n" % val.encode("utf8"))
87-
except AttributeError:
88-
txt.append("<td>%s</td>\n" % val)
82+
txt.append("<td>%s</td>\n" % val)
8983
if n > 1:
9084
txt.append("</tr>\n")
9185
n -= 1
@@ -206,7 +200,7 @@ def set_cookie(self, user):
206200
cookie[self.cookie_name]['path'] = "/"
207201
cookie[self.cookie_name]["expires"] = _expiration(480)
208202
logger.debug("Cookie expires: %s", cookie[self.cookie_name]["expires"])
209-
return cookie.output().encode("UTF-8").split(": ", 1)
203+
return cookie.output().split(": ", 1)
210204

211205

212206
# -----------------------------------------------------------------------------
@@ -230,12 +224,9 @@ def unpack_redirect(self):
230224
return None
231225

232226
def unpack_post(self):
233-
_dict = parse_qs(get_post(self.environ))
227+
_dict = parse_qs(get_post(self.environ).decode('utf8'))
234228
logger.debug("unpack_post:: %s", _dict)
235-
try:
236-
return dict([(k, v[0]) for k, v in _dict.items()])
237-
except Exception:
238-
return None
229+
return dict([(k, v[0]) for k, v in _dict.items()])
239230

240231
def unpack_soap(self):
241232
try:
@@ -544,7 +535,7 @@ def _pick_idp(self, came_from):
544535
return -1, SeeOther(loc)
545536
elif len(idps) == 1:
546537
# idps is a dictionary
547-
idp_entity_id = idps.keys()[0]
538+
idp_entity_id = list(idps.keys())[0]
548539
elif not len(idps):
549540
return -1, ServiceError('Misconfiguration')
550541
else:

src/saml2/config.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
#!/usr/bin/env python
2-
from saml2.saml import NAME_FORMAT_URI
3-
4-
__author__ = 'rolandh'
5-
62
import copy
73
import sys
84
import os
@@ -11,7 +7,7 @@
117
import logging.handlers
128
import six
139

14-
from importlib import import_module
10+
from future.backports.test.support import import_module
1511

1612
from saml2 import root_logger, BINDING_URI, SAMLError
1713
from saml2 import BINDING_SOAP
@@ -22,10 +18,13 @@
2218
from saml2.attribute_converter import ac_factory
2319
from saml2.assertion import Policy
2420
from saml2.mdstore import MetadataStore
21+
from saml2.saml import NAME_FORMAT_URI
2522
from saml2.virtual_org import VirtualOrg
2623

2724
logger = logging.getLogger(__name__)
2825

26+
__author__ = 'rolandh'
27+
2928

3029
COMMON_ARGS = [
3130
"entityid", "xmlsec_binary", "debug", "key_file", "cert_file",
@@ -493,6 +492,22 @@ def do_extensions(self, extensions):
493492
for key, val in extensions.items():
494493
self.extensions[key] = val
495494

495+
def service_per_endpoint(self, context=None):
496+
"""
497+
List all endpoint this entity publishes and which service and binding
498+
that are behind the endpoint
499+
500+
:param context: Type of entity
501+
:return: Dictionary with endpoint url as key and a tuple of
502+
service and binding as value
503+
"""
504+
endps = self.getattr("endpoints", context)
505+
res = {}
506+
for service, specs in endps.items():
507+
for endp, binding in specs:
508+
res[endp] = (service, binding)
509+
return res
510+
496511

497512
class SPConfig(Config):
498513
def_context = "sp"

src/saml2/httputil.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,21 @@ def _response(self, message="", **argv):
6464
else:
6565
if isinstance(message, six.string_types):
6666
return [message]
67+
elif isinstance(message, six.binary_type):
68+
return [message]
6769
else:
6870
return message
6971

72+
def add_header(self, ava):
73+
"""
74+
Does *NOT* replace a header of the same type, just adds a new
75+
:param ava: (type, value) tuple
76+
"""
77+
self.headers.append(ava)
78+
79+
def reply(self, **kwargs):
80+
return self.response(self.message, **kwargs)
81+
7082

7183
class Created(Response):
7284
_status = "201 Created"

src/saml2/mdstore.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
import json
77
import requests
88
import six
9+
910
from hashlib import sha1
1011
from os.path import isfile
1112
from os.path import join
1213

14+
from future.backports.test.support import import_module
15+
1316
from saml2 import md
1417
from saml2 import saml
1518
from saml2 import samlp
@@ -32,7 +35,6 @@
3235
from saml2.time_util import valid
3336
from saml2.validate import NotValid
3437
from saml2.sigver import security_context
35-
from importlib import import_module
3638

3739
__author__ = 'rolandh'
3840

@@ -225,7 +227,7 @@ def parse(self, xmlstr):
225227
'''
226228
raise NotImplementedError
227229

228-
def load(self):
230+
def load(self, *args, **kwargs):
229231
'''
230232
Loads the metadata
231233
'''
@@ -634,7 +636,7 @@ def __init__(self, attrc, filename=None, cert=None, **kwargs):
634636
def get_metadata_content(self):
635637
return open(self.filename, 'rb').read()
636638

637-
def load(self):
639+
def load(self, *args, **kwargs):
638640
_txt = self.get_metadata_content()
639641
return self.parse_and_check_signature(_txt)
640642

@@ -655,7 +657,7 @@ def __init__(self, attrc, loader_callable, cert=None,
655657

656658
@staticmethod
657659
def get_metadata_loader(func):
658-
if callable(func):
660+
if hasattr(func, '__call__'):
659661
return func
660662

661663
i = func.rfind('.')
@@ -673,7 +675,7 @@ def get_metadata_loader(func):
673675
'Module "%s" does not define a "%s" metadata loader' % (
674676
module, attr))
675677

676-
if not callable(metadata_loader):
678+
if not hasattr(metadata_loader, '__call__'):
677679
raise RuntimeError(
678680
'Metadata loader %s.%s must be callable' % (module, attr))
679681

@@ -710,7 +712,7 @@ def __init__(self, attrc, url=None, security=None, cert=None,
710712
self.security = security
711713
self.http = http
712714

713-
def load(self):
715+
def load(self, *args, **kwargs):
714716
""" Imports metadata by the use of HTTP GET.
715717
If the fingerprint is known the file will be checked for
716718
compliance before it is imported.
@@ -734,7 +736,7 @@ def __init__(self, attrc, filename, **kwargs):
734736
super(MetaDataMD, self).__init__(attrc, **kwargs)
735737
self.filename = filename
736738

737-
def load(self):
739+
def load(self, *args, **kwargs):
738740
for key, item in json.loads(open(self.filename).read()):
739741
self.entity[key] = item
740742

@@ -760,7 +762,7 @@ def __init__(self, url, entity_transform=None):
760762
concatenated with the request URL sent to the MDX server. Defaults to
761763
sha1 transformation.
762764
"""
763-
super(MetaDataMDX, self).__init__(None, None)
765+
super(MetaDataMDX, self).__init__(None, '')
764766
self.url = url
765767

766768
if entity_transform:
@@ -769,7 +771,7 @@ def __init__(self, url, entity_transform=None):
769771

770772
self.entity_transform = MetaDataMDX.sha1_entity_transform
771773

772-
def load(self):
774+
def load(self, *args, **kwargs):
773775
# Do nothing
774776
pass
775777

@@ -807,7 +809,7 @@ def __init__(self, attrc, config, ca_certs=None,
807809
:params ca_certs:
808810
:params disable_ssl_certificate_validation:
809811
"""
810-
self.attrc = attrc
812+
MetaData.__init__(self, attrc, check_validity=check_validity)
811813

812814
if disable_ssl_certificate_validation:
813815
self.http = HTTPBase(verify=False, ca_bundle=ca_certs)
@@ -821,12 +823,13 @@ def __init__(self, attrc, config, ca_certs=None,
821823
self.filter = filter
822824
self.to_old = {}
823825

824-
def load(self, typ, *args, **kwargs):
826+
def load(self, *args, **kwargs):
825827
if self.filter:
826828
_args = {"filter": self.filter}
827829
else:
828830
_args = {}
829831

832+
typ = args[0]
830833
if typ == "local":
831834
key = args[0]
832835
# if library read every file in the library

tests/test_19_attribute_converter.py

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
from attribute_statement_data import *
66

77
from pathutils import full_path
8-
from saml2.attribute_converter import AttributeConverterNOOP, AttributeConverter
8+
from saml2.attribute_converter import AttributeConverterNOOP
9+
from saml2.attribute_converter import AttributeConverter
910
from saml2.attribute_converter import to_local
1011
from saml2.saml import attribute_from_string
12+
from saml2.saml import attribute_statement_from_string
1113

1214

1315
def _eq(l1, l2):
@@ -118,44 +120,42 @@ def test_to_local_name(self):
118120

119121
attr = [
120122
saml.Attribute(
121-
friendly_name="surName",
122-
name="urn:oid:2.5.4.4",
123-
name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"),
123+
friendly_name="surName",
124+
name="urn:oid:2.5.4.4",
125+
name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"),
124126
saml.Attribute(
125-
friendly_name="efternamn",
126-
name="urn:oid:2.5.4.42",
127-
name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"),
127+
friendly_name="efternamn",
128+
name="urn:oid:2.5.4.42",
129+
name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"),
128130
saml.Attribute(
129-
friendly_name="titel",
130-
name="urn:oid:2.5.4.12",
131-
name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri")]
131+
friendly_name="titel",
132+
name="urn:oid:2.5.4.12",
133+
name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri")]
132134

133135
lan = [attribute_converter.to_local_name(self.acs, a) for a in attr]
134136

135137
assert _eq(lan, ['sn', 'givenName', 'title'])
136138

137-
# def test_ava_fro_1(self):
138-
#
139-
# attr = [saml.Attribute(friendly_name="surName",
140-
# name="urn:oid:2.5.4.4",
141-
# name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"),
142-
# saml.Attribute(friendly_name="efternamn",
143-
# name="urn:oid:2.5.4.42",
144-
# name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"),
145-
# saml.Attribute(friendly_name="titel",
146-
# name="urn:oid:2.5.4.12",
147-
# name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri")]
148-
#
149-
# result = attribute_converter.ava_fro(self.acs, attr)
150-
#
151-
# print(result)
152-
# assert result == {'givenName': [], 'sn': [], 'title': []}
139+
def test_to_local_name_from_unspecified(self):
140+
_xml = """<?xml version='1.0' encoding='UTF-8'?>
141+
<ns0:AttributeStatement xmlns:ns0="urn:oasis:names:tc:SAML:2.0:assertion">
142+
<ns0:Attribute
143+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
144+
Name="EmailAddress"
145+
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
146+
<ns0:AttributeValue xsi:type="xs:string">[email protected]</ns0:AttributeValue>
147+
</ns0:Attribute></ns0:AttributeStatement>"""
148+
149+
attr = attribute_statement_from_string(_xml)
150+
ava = attribute_converter.to_local(self.acs, attr)
151+
152+
assert _eq(list(ava.keys()), ['EmailAddress'])
153153

154154
def test_to_local_name_from_basic(self):
155155
attr = [
156156
saml.Attribute(
157-
name="urn:mace:dir:attribute-def:eduPersonPrimaryOrgUnitDN",
158-
name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:basic")
157+
name="urn:mace:dir:attribute-def:eduPersonPrimaryOrgUnitDN",
158+
name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:basic")
159159
]
160160

161161
lan = [attribute_converter.to_local_name(self.acs, a) for a in attr]
@@ -229,7 +229,12 @@ def test_noop_attribute_conversion():
229229

230230

231231
ava = """<?xml version='1.0' encoding='UTF-8'?>
232-
<ns0:Attribute xmlns:ns0="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" FriendlyName="schacHomeOrganization" Name="urn:oid:1.3.6.1.4.1.25178.1.2.9" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><ns0:AttributeValue xsi:nil="true" xsi:type="xs:string">uu.se</ns0:AttributeValue></ns0:Attribute>"""
232+
<ns0:Attribute xmlns:ns0="urn:oasis:names:tc:SAML:2.0:assertion"
233+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
234+
FriendlyName="schacHomeOrganization" Name="urn:oid:1.3.6.1.4.1.25178.1.2.9"
235+
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><ns0
236+
:AttributeValue xsi:nil="true"
237+
xsi:type="xs:string">uu.se</ns0:AttributeValue></ns0:Attribute>"""
233238

234239

235240
def test_schac():
@@ -246,5 +251,4 @@ def test_schac():
246251
if __name__ == "__main__":
247252
t = TestAC()
248253
t.setup_class()
249-
t.test_to_attrstat_1()
250-
# test_schac()
254+
t.test_to_local_name_from_unspecified()

0 commit comments

Comments
 (0)