Skip to content

Commit 82d3b4d

Browse files
author
Roland Hedberg
committed
Merge branch 'master' of github.com:rohe/pysaml2
2 parents 883b89e + e6151b5 commit 82d3b4d

File tree

7 files changed

+121
-82
lines changed

7 files changed

+121
-82
lines changed

doc/howto/config.rst

+17-2
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,23 @@ This directive has as value a dictionary with one or more of the following keys:
452452
* single_logout_service (aa, idp, sp)
453453
* single_sign_on_service (idp)
454454

455-
The values per service is a list of tuples containing endpoint and binding
456-
type.
455+
The values per service is a list of endpoint specifications.
456+
An endpoint specification can either be just the URL::
457+
458+
”http://localhost:8088/A"
459+
460+
or it can be a 2-tuple (URL+binding)::
461+
462+
from saml2 import BINDING_HTTP_POST
463+
(”http://localhost:8087/A”, BINDING_HTTP_POST)
464+
465+
or a 3-tuple (URL+binding+index)::
466+
467+
from saml2 import BINDING_HTTP_POST
468+
(”http://lingon.catalogix.se:8087/A”, BINDING_HTTP_POST, 1)
469+
470+
If no binding is specified, no index can be set.
471+
If no index is specified, the index is set based on the position in the list.
457472

458473
Example::
459474

example/idp2/idp_user.py

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#from dirg_util.dict import LDAPDict
2-
#ldap_settings = {
1+
# from dirg_util.dict import LDAPDict
2+
# ldap_settings = {
33
# "ldapuri": "ldaps://ldap.test.umu.se",
44
# "base": "dc=umu, dc=se",
55
# "filter_pattern": "(uid=%s)",
@@ -30,9 +30,9 @@
3030
# "exact_match": True,
3131
# "firstonly_len1": True,
3232
# "timeout": 15,
33-
#}
34-
#Uncomment to use a LDAP directory instead.
35-
#USERS = LDAPDict(**ldap_settings)
33+
# }
34+
# Uncomment to use a LDAP directory instead.
35+
# USERS = LDAPDict(**ldap_settings)
3636

3737
USERS = {
3838
"testuser": {
@@ -54,7 +54,9 @@
5454
"email": "[email protected]",
5555
"displayName": "Test Testsson",
5656
"labeledURL": "http://www.example.com/test My homepage",
57-
"norEduPersonNIN": "SE199012315555"
57+
"norEduPersonNIN": "SE199012315555",
58+
"postaladdress": "postaladdress",
59+
"cn": "cn"
5860
},
5961
"roland": {
6062
"sn": "Hedberg",
@@ -67,7 +69,7 @@
6769
"o": "Example Co.",
6870
"ou": "IT",
6971
"initials": "P",
70-
#"schacHomeOrganization": "example.com",
72+
# "schacHomeOrganization": "example.com",
7173
"mail": "[email protected]",
7274
"displayName": "P. Roland Hedberg",
7375
"labeledURL": "http://www.example.com/rohe My homepage",
@@ -91,4 +93,4 @@
9193
"schacGender": "male",
9294
"schacUserPresenceID": "skype:pepe.perez"
9395
}
94-
}
96+
}

example/sp-wsgi/sp.py

+71-64
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,47 @@
11
#!/usr/bin/env python
22
from __future__ import print_function
3-
import logging
4-
import re
3+
54
import argparse
5+
import importlib
6+
import logging
67
import os
7-
try:
8-
from future.backports.http.cookies import SimpleCookie
9-
except:
10-
from Cookie import SimpleCookie
11-
import six
12-
13-
from saml2.extension.pefim import SPCertEnc
14-
from saml2.metadata import create_metadata_string
15-
import service_conf
8+
import re
9+
import sys
1610

11+
import six
12+
from six.moves.http_cookies import SimpleCookie
1713
from six.moves.urllib.parse import parse_qs
18-
import sys
1914

15+
import saml2.xmldsig as ds
16+
from saml2 import BINDING_HTTP_ARTIFACT
17+
from saml2 import BINDING_HTTP_POST
2018
from saml2 import BINDING_HTTP_REDIRECT, element_to_extension_element
2119
from saml2 import BINDING_SOAP
22-
from saml2 import time_util
2320
from saml2 import ecp
24-
from saml2 import BINDING_HTTP_ARTIFACT
25-
from saml2 import BINDING_HTTP_POST
21+
from saml2 import time_util
2622
from saml2.client import Saml2Client
2723
from saml2.ecp_client import PAOS_HEADER_INFO
28-
from saml2.httputil import geturl, make_cookie, parse_cookie
29-
from saml2.httputil import get_post
30-
from saml2.httputil import Response
24+
from saml2.extension.pefim import SPCertEnc
3125
from saml2.httputil import BadRequest
32-
from saml2.httputil import ServiceError
33-
from saml2.httputil import SeeOther
34-
from saml2.httputil import Unauthorized
3526
from saml2.httputil import NotFound
36-
from saml2.httputil import Redirect
3727
from saml2.httputil import NotImplemented
28+
from saml2.httputil import Redirect
29+
from saml2.httputil import Response
30+
from saml2.httputil import SeeOther
31+
from saml2.httputil import ServiceError
32+
from saml2.httputil import Unauthorized
33+
from saml2.httputil import get_post
34+
from saml2.httputil import geturl, make_cookie, parse_cookie
35+
from saml2.metadata import create_metadata_string
3836
from saml2.response import StatusError
3937
from saml2.response import VerificationError
4038
from saml2.s_utils import UnknownPrincipal
41-
from saml2.s_utils import decode_base64_and_inflate
4239
from saml2.s_utils import UnsupportedBinding
43-
from saml2.s_utils import sid
40+
from saml2.s_utils import decode_base64_and_inflate
4441
from saml2.s_utils import rndstr
45-
#from srtest import exception_trace
42+
from saml2.s_utils import sid
43+
from saml2.saml import NAMEID_FORMAT_PERSISTENT
4644
from saml2.samlp import Extensions
47-
from saml2 import xmldsig as ds
48-
import saml2.xmldsig as ds
4945

5046
logger = logging.getLogger("")
5147
hdlr = logging.FileHandler('spx.log')
@@ -56,7 +52,6 @@
5652
logger.addHandler(hdlr)
5753
logger.setLevel(logging.INFO)
5854

59-
6055
SP = None
6156
SEED = ""
6257
POLICY = None
@@ -141,7 +136,7 @@ class ECPResponse(object):
141136
def __init__(self, content):
142137
self.content = content
143138

144-
#noinspection PyUnusedLocal
139+
# noinspection PyUnusedLocal
145140
def __call__(self, environ, start_response):
146141
start_response('%s %s' % (self.code, self.title),
147142
[('Content-Type', "text/xml")])
@@ -172,7 +167,6 @@ def __init__(self):
172167

173168
def get_user(self, environ):
174169
cookie = environ.get("HTTP_COOKIE", '')
175-
cookie = cookie.decode("UTF-8")
176170
logger.debug("Cookie: %s", cookie)
177171
if cookie:
178172
cookie_obj = SimpleCookie(cookie)
@@ -354,7 +348,7 @@ def do(self, response, binding, relay_state="", mtype="response"):
354348
:param response: The SAML response, transport encoded
355349
:param binding: Which binding the query came in over
356350
"""
357-
#tmp_outstanding_queries = dict(self.outstanding_queries)
351+
# tmp_outstanding_queries = dict(self.outstanding_queries)
358352
if not response:
359353
logger.info("Missing Response")
360354
resp = Unauthorized('Unknown user')
@@ -408,6 +402,7 @@ def verify_attributes(self, ava):
408402

409403
return res
410404

405+
411406
# -----------------------------------------------------------------------------
412407
# REQUESTERS
413408
# -----------------------------------------------------------------------------
@@ -557,7 +552,7 @@ def redirect_to_auth(self, _cli, entity_id, came_from, sigalg=""):
557552
"single_sign_on_service", self.bindings, "idpsso",
558553
entity_id=entity_id)
559554
logger.debug("binding: %s, destination: %s", _binding,
560-
destination)
555+
destination)
561556
# Binding here is the response binding that is which binding the
562557
# IDP should use to return the response.
563558
acs = _cli.config.getattr("endpoints", "sp")[
@@ -568,19 +563,20 @@ def redirect_to_auth(self, _cli, entity_id, came_from, sigalg=""):
568563
extensions = None
569564
cert = None
570565
if _cli.config.generate_cert_func is not None:
571-
cert_str, req_key_str = _cli.config.generate_cert_func()
572-
cert = {
573-
"cert": cert_str,
574-
"key": req_key_str
575-
}
576-
spcertenc = SPCertEnc(x509_data=ds.X509Data(
577-
x509_certificate=ds.X509Certificate(text=cert_str)))
578-
extensions = Extensions(extension_elements=[
579-
element_to_extension_element(spcertenc)])
566+
cert_str, req_key_str = _cli.config.generate_cert_func()
567+
cert = {
568+
"cert": cert_str,
569+
"key": req_key_str
570+
}
571+
spcertenc = SPCertEnc(x509_data=ds.X509Data(
572+
x509_certificate=ds.X509Certificate(text=cert_str)))
573+
extensions = Extensions(extension_elements=[
574+
element_to_extension_element(spcertenc)])
580575

581576
req_id, req = _cli.create_authn_request(destination,
582577
binding=return_binding,
583-
extensions=extensions)
578+
extensions=extensions,
579+
nameid_format=NAMEID_FORMAT_PERSISTENT)
584580
_rstate = rndstr()
585581
self.cache.relay_state[_rstate] = came_from
586582
ht_args = _cli.apply_binding(_binding, "%s" % req, destination,
@@ -639,7 +635,7 @@ def do(self, message, binding, relay_state="", mtype="response"):
639635
try:
640636
txt = decode_base64_and_inflate(message)
641637
is_logout_request = 'LogoutRequest' in txt.split('>', 1)[0]
642-
except: # TODO: parse the XML correctly
638+
except: # TODO: parse the XML correctly
643639
is_logout_request = False
644640

645641
if is_logout_request:
@@ -649,10 +645,11 @@ def do(self, message, binding, relay_state="", mtype="response"):
649645

650646
return finish_logout(self.environ, self.start_response)
651647

648+
652649
# ----------------------------------------------------------------------------
653650

654651

655-
#noinspection PyUnusedLocal
652+
# noinspection PyUnusedLocal
656653
def not_found(environ, start_response):
657654
"""Called if no URL matches."""
658655
resp = NotFound('Not Found')
@@ -662,7 +659,7 @@ def not_found(environ, start_response):
662659
# ----------------------------------------------------------------------------
663660

664661

665-
#noinspection PyUnusedLocal
662+
# noinspection PyUnusedLocal
666663
def main(environ, start_response, sp):
667664
user = CACHE.get_user(environ)
668665

@@ -690,10 +687,11 @@ def disco(environ, start_response, _sp):
690687
resp.headers.append(kaka)
691688
return resp(environ, start_response)
692689

690+
693691
# ----------------------------------------------------------------------------
694692

695693

696-
#noinspection PyUnusedLocal
694+
# noinspection PyUnusedLocal
697695
def logout(environ, start_response, sp):
698696
user = CACHE.get_user(environ)
699697

@@ -740,10 +738,11 @@ def finish_logout(environ, start_response):
740738
cookie = CACHE.delete_cookie(environ)
741739

742740
resp = Response('You are now logged out of this service', headers=[
743-
cookie,
741+
cookie,
744742
])
745743
return resp(environ, start_response)
746744

745+
747746
# ----------------------------------------------------------------------------
748747

749748
# map urls to functions
@@ -771,16 +770,17 @@ def add_urls():
771770
urls.append(("%s/redirect$" % base, (SLO, "redirect", SP)))
772771
urls.append(("%s/redirect/(.*)$" % base, (SLO, "redirect", SP)))
773772

773+
774774
# ----------------------------------------------------------------------------
775775

776776
def metadata(environ, start_response):
777777
try:
778778
path = _args.path
779779
if path is None or len(path) == 0:
780-
path = os.path.dirname(os.path.abspath( __file__ ))
780+
path = os.path.dirname(os.path.abspath(__file__))
781781
if path[-1] != "/":
782782
path += "/"
783-
metadata = create_metadata_string(path+"sp_conf.py", None,
783+
metadata = create_metadata_string(path + "sp_conf.py", None,
784784
_args.valid, _args.cert, _args.keyfile,
785785
_args.id, _args.name, _args.sign)
786786
start_response('200 OK', [('Content-Type', "text/xml")])
@@ -789,6 +789,7 @@ def metadata(environ, start_response):
789789
logger.error("An error occured while creating metadata: %s", ex.message)
790790
return not_found(environ, start_response)
791791

792+
792793
def application(environ, start_response):
793794
"""
794795
The main WSGI application. Dispatch the current request to
@@ -827,27 +828,15 @@ def application(environ, start_response):
827828
resp = BadRequest("%s" % err)
828829
return resp(environ, start_response)
829830
except Exception as err:
830-
#_err = exception_trace("RUN", err)
831-
#logging.error(exception_trace("RUN", _err))
831+
# _err = exception_trace("RUN", err)
832+
# logging.error(exception_trace("RUN", _err))
832833
print(err, file=sys.stderr)
833834
resp = ServiceError("%s" % err)
834835
return resp(environ, start_response)
835836

836-
# ----------------------------------------------------------------------------
837-
838-
HOST = service_conf.HOST
839-
PORT = service_conf.PORT
840-
# ------- HTTPS -------
841-
# These should point to relevant files
842-
SERVER_CERT = service_conf.SERVER_CERT
843-
SERVER_KEY = service_conf.SERVER_KEY
844-
# This is of course the certificate chain for the CA that signed
845-
# your cert and all the way up to the top
846-
CERT_CHAIN = service_conf.CERT_CHAIN
847837

848838
if __name__ == '__main__':
849839
from cherrypy import wsgiserver
850-
from cherrypy.wsgiserver import ssl_pyopenssl
851840

852841
_parser = argparse.ArgumentParser()
853842
_parser.add_argument('-d', dest='debug', action='store_true',
@@ -870,7 +859,8 @@ def application(environ, start_response):
870859
_parser.add_argument('-n', dest='name')
871860
_parser.add_argument('-S', dest='sign', action='store_true',
872861
help="sign the metadata")
873-
862+
_parser.add_argument('-C', dest='service_conf_module',
863+
help="service config module")
874864

875865
ARGS = {}
876866
_args = _parser.parse_args()
@@ -886,6 +876,21 @@ def application(environ, start_response):
886876
else:
887877
SEED = "SnabbtInspel"
888878

879+
if _args.service_conf_module:
880+
service_conf = importlib.import_module(_args.service_conf_module)
881+
else:
882+
import service_conf
883+
884+
HOST = service_conf.HOST
885+
PORT = service_conf.PORT
886+
# ------- HTTPS -------
887+
# These should point to relevant files
888+
SERVER_CERT = service_conf.SERVER_CERT
889+
SERVER_KEY = service_conf.SERVER_KEY
890+
# This is of course the certificate chain for the CA that signed
891+
# your cert and all the way up to the top
892+
CERT_CHAIN = service_conf.CERT_CHAIN
893+
889894
SP = Saml2Client(config_file="%s" % CNFBASE)
890895

891896
POLICY = service_conf.POLICY
@@ -907,6 +912,8 @@ def application(environ, start_response):
907912

908913
_https = ""
909914
if service_conf.HTTPS:
915+
from cherrypy.wsgiserver import ssl_pyopenssl
916+
910917
SRV.ssl_adapter = ssl_pyopenssl.pyOpenSSLAdapter(SERVER_CERT,
911918
SERVER_KEY, CERT_CHAIN)
912919
_https = " using SSL/TLS"

src/saml2/client_base.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,9 @@ def create_authn_request(self, destination, vorg="", scoping=None,
243243
del kwargs["assertion_consumer_service_url"]
244244
except KeyError:
245245
try:
246-
args["attribute_consuming_service_index"] = str(kwargs[
247-
"attribute_consuming_service_index"])
248-
del kwargs["attribute_consuming_service_index"]
246+
args["assertion_consumer_service_index"] = str(kwargs[
247+
"assertion_consumer_service_index"])
248+
del kwargs["assertion_consumer_service_index"]
249249
except KeyError:
250250
if service_url_binding is None:
251251
service_urls = self.service_urls(binding)

0 commit comments

Comments
 (0)