Skip to content

Commit 0f34abb

Browse files
author
Roland Hedberg
committed
Handle different problems pointed out by Seth Arnold.
1 parent 7f4e595 commit 0f34abb

File tree

4 files changed

+75
-49
lines changed

4 files changed

+75
-49
lines changed

example/idp2/idp.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from saml2 import BINDING_HTTP_POST
2121
from saml2 import server
2222
from saml2 import time_util
23+
from saml2.authn import is_equal
2324

2425
from saml2.authn_context import AuthnBroker
2526
from saml2.authn_context import PASSWORD
@@ -131,20 +132,20 @@ def operation(self, saml_msg, binding):
131132
else:
132133
# saml_msg may also contain Signature and SigAlg
133134
if "Signature" in saml_msg:
134-
args = {"signature": saml_msg["signature"],
135+
kwargs = {"signature": saml_msg["signature"],
135136
"sigalg": saml_msg["SigAlg"]}
136137
else:
137-
args = {}
138+
kwargs = {}
138139
try:
139140
_encrypt_cert = encrypt_cert_from_item(
140141
saml_msg["req_info"].message)
141142
return self.do(saml_msg["SAMLRequest"], binding,
142143
saml_msg["RelayState"],
143-
encrypt_cert=_encrypt_cert, **args)
144+
encrypt_cert=_encrypt_cert, **kwargs)
144145
except KeyError:
145146
# Can live with no relay state # TODO or can we, for inacademia?
146147
return self.do(saml_msg["SAMLRequest"], binding,
147-
saml_msg["RelayState"], **args)
148+
saml_msg["RelayState"], **kwargs)
148149

149150
def artifact_operation(self, saml_msg):
150151
if not saml_msg:
@@ -454,10 +455,9 @@ def ecp(self):
454455
except TypeError:
455456
resp = Unauthorized()
456457
else:
457-
logger.debug("Authz_info: %s" % _info)
458458
try:
459459
(user, passwd) = _info.split(":")
460-
if PASSWD[user] != passwd:
460+
if is_equal(PASSWD[user], passwd):
461461
resp = Unauthorized()
462462
self.user = user
463463
self.environ[
@@ -931,12 +931,16 @@ def metadata(environ, start_response):
931931

932932
def staticfile(environ, start_response):
933933
try:
934-
path = args.path
934+
path = args.path[:]
935935
if path is None or len(path) == 0:
936936
path = os.path.dirname(os.path.abspath(__file__))
937937
if path[-1] != "/":
938938
path += "/"
939939
path += environ.get('PATH_INFO', '').lstrip('/')
940+
path = os.path.realpath(path)
941+
if not path.startswith(args.path):
942+
resp = Unauthorized()
943+
return resp(environ, start_response)
940944
start_response('200 OK', [('Content-Type', "text/xml")])
941945
return open(path, 'r').read()
942946
except Exception as ex:

example/idp2/idp_uwsgi.py

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from urlparse import parse_qs
1111
from Cookie import SimpleCookie
1212
import os
13+
from saml2.authn import is_equal
1314
from saml2.profile import ecp
1415

1516
from saml2 import server
@@ -73,12 +74,14 @@ def get_eptid(idp, req_info, session):
7374
req_info.sender(), session["permanent_id"],
7475
session["authn_auth"])
7576

77+
7678
# -----------------------------------------------------------------------------
7779

7880

7981
def dict2list_of_tuples(d):
8082
return [(k, v) for k, v in d.items()]
8183

84+
8285
# -----------------------------------------------------------------------------
8386

8487

@@ -95,22 +98,22 @@ def unpack_redirect(self):
9598
return dict([(k, v[0]) for k, v in parse_qs(_qs).items()])
9699
else:
97100
return None
98-
101+
99102
def unpack_post(self):
100103
_dict = parse_qs(get_post(self.environ))
101104
logger.debug("unpack_post:: %s" % _dict)
102105
try:
103106
return dict([(k, v[0]) for k, v in _dict.items()])
104107
except Exception:
105108
return None
106-
109+
107110
def unpack_soap(self):
108111
try:
109112
query = get_post(self.environ)
110113
return {"SAMLRequest": query, "RelayState": ""}
111114
except Exception:
112115
return None
113-
116+
114117
def unpack_either(self):
115118
if self.environ["REQUEST_METHOD"] == "GET":
116119
_dict = self.unpack_redirect()
@@ -292,7 +295,7 @@ def do(self, query, binding_in, relay_state="", encrypt_cert=None):
292295

293296
if not _resp:
294297
identity = USERS[self.user].copy()
295-
#identity["eduPersonTargetedID"] = get_eptid(IDP, query, session)
298+
# identity["eduPersonTargetedID"] = get_eptid(IDP, query, session)
296299
logger.info("Identity: %s" % (identity,))
297300

298301
if REPOZE_ID_EQUIVALENT:
@@ -357,7 +360,8 @@ def redirect(self):
357360

358361
_req = self.req_info.message
359362

360-
if "SigAlg" in saml_msg and "Signature" in saml_msg: # Signed request
363+
if "SigAlg" in saml_msg and "Signature" in saml_msg: # Signed
364+
# request
361365
issuer = _req.issuer.text
362366
_certs = IDP.metadata.certs(issuer, "any", "signing")
363367
verified_ok = False
@@ -405,7 +409,7 @@ def post(self):
405409
return self.not_authn(key, _req.requested_authn_context)
406410

407411
# def artifact(self):
408-
# # Can be either by HTTP_Redirect or HTTP_POST
412+
# # Can be either by HTTP_Redirect or HTTP_POST
409413
# _req = self._store_request(self.unpack_either())
410414
# if isinstance(_req, basestring):
411415
# return self.not_authn(_req)
@@ -424,10 +428,9 @@ def ecp(self):
424428
except TypeError:
425429
resp = Unauthorized()
426430
else:
427-
logger.debug("Authz_info: %s" % _info)
428431
try:
429432
(user, passwd) = _info.split(":")
430-
if PASSWD[user] != passwd:
433+
if is_equal(PASSWD[user], passwd):
431434
resp = Unauthorized()
432435
self.user = user
433436
self.environ[
@@ -449,6 +452,7 @@ def ecp(self):
449452
self.op_type = "ecp"
450453
return self.operation(_dict, BINDING_SOAP)
451454

455+
452456
# -----------------------------------------------------------------------------
453457
# === Authentication ====
454458
# -----------------------------------------------------------------------------
@@ -474,11 +478,11 @@ def do_authentication(environ, start_response, authn_context, key,
474478
# -----------------------------------------------------------------------------
475479

476480
PASSWD = {
477-
"daev0001": "qwerty",
478-
"haho0032": "qwerty",
479-
"roland": "dianakra",
480-
"babs": "howes",
481-
"upper": "crust"}
481+
"daev0001": "qwerty",
482+
"haho0032": "qwerty",
483+
"roland": "dianakra",
484+
"babs": "howes",
485+
"upper": "crust"}
482486

483487

484488
def username_password_authn(environ, start_response, reference, key,
@@ -552,7 +556,7 @@ def not_found(environ, start_response):
552556
# === Single log out ===
553557
# -----------------------------------------------------------------------------
554558

555-
#def _subject_sp_info(req_info):
559+
# def _subject_sp_info(req_info):
556560
# # look for the subject
557561
# subject = req_info.subject_id()
558562
# subject = subject.text.strip()
@@ -570,7 +574,7 @@ def do(self, request, binding, relay_state="", encrypt_cert=None):
570574
logger.error("Bad request: %s" % exc)
571575
resp = BadRequest("%s" % exc)
572576
return resp(self.environ, self.start_response)
573-
577+
574578
msg = req_info.message
575579
if msg.name_id:
576580
lid = IDP.ident.find_local_id(msg.name_id)
@@ -587,52 +591,53 @@ def do(self, request, binding, relay_state="", encrypt_cert=None):
587591
logger.error("ServiceError: %s" % exc)
588592
resp = ServiceError("%s" % exc)
589593
return resp(self.environ, self.start_response)
590-
594+
591595
resp = IDP.create_logout_response(msg, [binding])
592-
596+
593597
try:
594598
hinfo = IDP.apply_binding(binding, "%s" % resp, "", relay_state)
595599
except Exception as exc:
596600
logger.error("ServiceError: %s" % exc)
597601
resp = ServiceError("%s" % exc)
598602
return resp(self.environ, self.start_response)
599-
603+
600604
#_tlh = dict2list_of_tuples(hinfo["headers"])
601605
delco = delete_cookie(self.environ, "idpauthn")
602606
if delco:
603607
hinfo["headers"].append(delco)
604608
logger.info("Header: %s" % (hinfo["headers"],))
605609
resp = Response(hinfo["data"], headers=hinfo["headers"])
606610
return resp(self.environ, self.start_response)
607-
611+
612+
608613
# ----------------------------------------------------------------------------
609614
# Manage Name ID service
610615
# ----------------------------------------------------------------------------
611616

612617

613618
class NMI(Service):
614-
615619
def do(self, query, binding, relay_state="", encrypt_cert=None):
616620
logger.info("--- Manage Name ID Service ---")
617621
req = IDP.parse_manage_name_id_request(query, binding)
618622
request = req.message
619-
623+
620624
# Do the necessary stuff
621625
name_id = IDP.ident.handle_manage_name_id_request(
622626
request.name_id, request.new_id, request.new_encrypted_id,
623627
request.terminate)
624-
628+
625629
logger.debug("New NameID: %s" % name_id)
626-
630+
627631
_resp = IDP.create_manage_name_id_response(request)
628-
632+
629633
# It's using SOAP binding
630634
hinfo = IDP.apply_binding(BINDING_SOAP, "%s" % _resp, "",
631635
relay_state, response=True)
632-
636+
633637
resp = Response(hinfo["data"], headers=hinfo["headers"])
634638
return resp(self.environ, self.start_response)
635-
639+
640+
636641
# ----------------------------------------------------------------------------
637642
# === Assertion ID request ===
638643
# ----------------------------------------------------------------------------
@@ -648,9 +653,9 @@ def do(self, aid, binding, relay_state="", encrypt_cert=None):
648653
except Unknown:
649654
resp = NotFound(aid)
650655
return resp(self.environ, self.start_response)
651-
656+
652657
hinfo = IDP.apply_binding(BINDING_URI, "%s" % assertion, response=True)
653-
658+
654659
logger.debug("HINFO: %s" % hinfo)
655660
resp = Response(hinfo["data"], headers=hinfo["headers"])
656661
return resp(self.environ, self.start_response)
@@ -680,6 +685,7 @@ def do(self, request, binding, relay_state="", encrypt_cert=None):
680685
resp = Response(hinfo["data"], headers=hinfo["headers"])
681686
return resp(self.environ, self.start_response)
682687

688+
683689
# ----------------------------------------------------------------------------
684690
# === Authn query service ===
685691
# ----------------------------------------------------------------------------
@@ -734,6 +740,7 @@ def do(self, request, binding, relay_state="", encrypt_cert=None):
734740
resp = Response(hinfo["data"], headers=hinfo["headers"])
735741
return resp(self.environ, self.start_response)
736742

743+
737744
# ----------------------------------------------------------------------------
738745
# Name ID Mapping service
739746
# When an entity that shares an identifier for a principal with an identity
@@ -757,17 +764,17 @@ def do(self, query, binding, relay_state="", encrypt_cert=None):
757764
except PolicyError:
758765
resp = BadRequest("Unknown entity")
759766
return resp(self.environ, self.start_response)
760-
767+
761768
info = IDP.response_args(request)
762769
_resp = IDP.create_name_id_mapping_response(name_id, **info)
763-
770+
764771
# Only SOAP
765772
hinfo = IDP.apply_binding(BINDING_SOAP, "%s" % _resp, "", "",
766773
response=True)
767-
774+
768775
resp = Response(hinfo["data"], headers=hinfo["headers"])
769776
return resp(self.environ, self.start_response)
770-
777+
771778

772779
# ----------------------------------------------------------------------------
773780
# Cookie handling
@@ -862,10 +869,10 @@ def metadata(environ, start_response):
862869
try:
863870
path = args.path
864871
if path is None or len(path) == 0:
865-
path = os.path.dirname(os.path.abspath( __file__ ))
872+
path = os.path.dirname(os.path.abspath(__file__))
866873
if path[-1] != "/":
867874
path += "/"
868-
metadata = create_metadata_string(path+args.config, IDP.config,
875+
metadata = create_metadata_string(path + args.config, IDP.config,
869876
args.valid, args.cert, args.keyfile,
870877
args.id, args.name, args.sign)
871878
start_response('200 OK', [('Content-Type', "text/xml")])
@@ -874,6 +881,7 @@ def metadata(environ, start_response):
874881
logger.error("An error occured while creating metadata:" + ex.message)
875882
return not_found(environ, start_response)
876883

884+
877885
def staticfile(environ, start_response):
878886
try:
879887
path = args.path
@@ -882,12 +890,17 @@ def staticfile(environ, start_response):
882890
if path[-1] != "/":
883891
path += "/"
884892
path += environ.get('PATH_INFO', '').lstrip('/')
893+
path = os.path.realpath(path)
894+
if not path.startswith(args.path):
895+
resp = Unauthorized()
896+
return resp(environ, start_response)
885897
start_response('200 OK', [('Content-Type', "text/xml")])
886898
return open(path, 'r').read()
887899
except Exception as ex:
888900
logger.error("An error occured while creating metadata:" + ex.message)
889901
return not_found(environ, start_response)
890902

903+
891904
def application(environ, start_response):
892905
"""
893906
The main WSGI application. Dispatch the current request to
@@ -924,7 +937,6 @@ def application(environ, start_response):
924937
except KeyError:
925938
user = None
926939

927-
928940
url_patterns = AUTHN_URLS
929941
if not user:
930942
logger.info("-- No USER --")
@@ -956,7 +968,7 @@ def application(environ, start_response):
956968
# by moving some initialization out of __name__ == '__main__' section.
957969
# uwsgi -s 0.0.0.0:8088 --protocol http --callable application --module idp
958970

959-
args = type('Config', (object,), { })
971+
args = type('Config', (object,), {})
960972
args.config = 'idp_conf'
961973
args.mako_root = './'
962974
args.path = None
@@ -984,7 +996,8 @@ def application(environ, start_response):
984996
parser = argparse.ArgumentParser()
985997
parser.add_argument('-p', dest='path', help='Path to configuration file.')
986998
parser.add_argument('-v', dest='valid',
987-
help="How long, in days, the metadata is valid from the time of creation")
999+
help="How long, in days, the metadata is valid from "
1000+
"the time of creation")
9881001
parser.add_argument('-c', dest='cert', help='certificate')
9891002
parser.add_argument('-i', dest='id',
9901003
help="The ID of the entities descriptor")

example/idp2_repoze/idp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from saml2 import BINDING_HTTP_REDIRECT
2020
from saml2 import BINDING_HTTP_POST
2121
from saml2 import time_util
22+
from saml2.authn import is_equal
2223

2324
from saml2.authn_context import AuthnBroker
2425
from saml2.authn_context import PASSWORD
@@ -414,7 +415,7 @@ def ecp(self):
414415
logger.debug("Authz_info: %s" % _info)
415416
try:
416417
(user, passwd) = _info.split(":")
417-
if PASSWD[user] != passwd:
418+
if is_equal(PASSWD[user], passwd):
418419
resp = Unauthorized()
419420
self.user = user
420421
except (ValueError, TypeError):

0 commit comments

Comments
 (0)