diff --git a/example/idp/idp.py b/example/idp/idp.py deleted file mode 100755 index 6dbcd3b..0000000 --- a/example/idp/idp.py +++ /dev/null @@ -1,304 +0,0 @@ -#!/usr/bin/env python - -import re -import logging - -#from cgi import parse_qs -from urlparse import parse_qs -from saml2.httputil import Unauthorized, NotFound, BadRequest -from saml2.httputil import ServiceError -from saml2.httputil import Response -from saml2.pack import http_form_post_message -from saml2.saml import AUTHN_PASSWORD -from saml2 import server -from saml2 import BINDING_HTTP_REDIRECT, BINDING_HTTP_POST -from saml2 import time_util -from Cookie import SimpleCookie - -logger = logging.getLogger("saml2.IDP") - -AUTHN = (AUTHN_PASSWORD, "http://www.example.com/login") - -def _expiration(timeout, format=None): - if timeout == "now": - return time_util.instant(format) - else: - # validity time should match lifetime of assertions - return time_util.in_a_while(minutes=timeout, format=format) - -# ----------------------------------------------------------------------------- -def dict_to_table(ava, lev=0, width=1): - txt = ['\n' % width] - for prop, valarr in ava.items(): - txt.append("\n") - if isinstance(valarr, basestring): - txt.append("\n" % str(prop)) - try: - txt.append("\n" % valarr.encode("utf8")) - except AttributeError: - txt.append("\n" % valarr) - elif isinstance(valarr, list): - index = 0 - num = len(valarr) - for val in valarr: - if not index: - txt.append("\n") - if isinstance(val, dict): - txt.append("\n") - else: - try: - txt.append("\n" % val.encode("utf8")) - except AttributeError: - txt.append("\n" % val) - if num > 1: - txt.append("\n") - num -= 1 - index += 1 - elif isinstance(valarr, dict): - txt.append("\n" % prop) - txt.append("\n") - txt.append("\n") - txt.append('
%s%s%s%s\n" % (len(valarr), prop)) - else: - txt.append("
\n") - txt.extend(dict_to_table(val, lev+1, width-1)) - txt.append("%s%s
%s\n") - txt.extend(dict_to_table(valarr, lev+1, width-1)) - txt.append("
\n') - return txt - -REPOZE_ID_EQUIVALENT = "uid" -FORM_SPEC = """
- - -
""" - - -def sso(environ, start_response, user): - """ Supposed to return a self issuing Form POST """ - #edict = dict_to_table(environ) - #if logger: logger.info("Environ keys: %s" % environ.keys()) - logger.info("--- In SSO ---") - query = None - if "QUERY_STRING" in environ: - if logger: - logger.info("Query string: %s" % environ["QUERY_STRING"]) - query = parse_qs(environ["QUERY_STRING"]) - elif "s2repoze.qinfo" in environ: - query = environ["s2repoze.qinfo"] - - if not query: - resp = Unauthorized('Unknown user') - return resp(environ, start_response) - - # base 64 encoded request - # Assume default binding, that is HTTP-redirect - req = IDP.parse_authn_request(query["SAMLRequest"][0]) - - if req is None: - resp = ServiceError("Failed to parse the SAML request") - return resp(environ, start_response) - - logger.info("parsed OK") - logger.info("%s" % req) - - identity = dict(environ["repoze.who.identity"]["user"]) - logger.info("Identity: %s" % (identity,)) - userid = environ["repoze.who.identity"]['repoze.who.userid'] - if REPOZE_ID_EQUIVALENT: - identity[REPOZE_ID_EQUIVALENT] = userid - - # What's the binding ? ProtocolBinding - if req.message.protocol_binding == BINDING_HTTP_REDIRECT: - _binding = BINDING_HTTP_POST - else: - _binding = req.message.protocol_binding - - try: - resp_args = IDP.response_args(req.message, [_binding]) - except Exception: - raise - - if req.message.assertion_consumer_service_url: - if req.message.assertion_consumer_service_url != resp_args["destination"]: - # serious error on someones behalf - logger.error("%s != %s" % (req.message.assertion_consumer_service_url, - resp_args["destination"])) - resp = BadRequest("ConsumerURL and return destination mismatch") - raise resp(environ, start_response) - - try: - authn_resp = IDP.create_authn_response(identity, userid=userid, - authn=AUTHN, **resp_args) - except Exception, excp: - logger.error("Exception: %s" % (excp,)) - raise - - logger.info("AuthNResponse: %s" % authn_resp) - - http_args = http_form_post_message(authn_resp, resp_args["destination"], - relay_state=query["RelayState"][0], - typ="SAMLResponse") - - resp = Response(http_args["data"], headers=http_args["headers"]) - return resp(environ, start_response) - -def whoami(environ, start_response, user): - identity = environ["repoze.who.identity"].copy() - for prop in ["login", "password"]: - try: - del identity[prop] - except KeyError: - continue - response = Response(dict_to_table(identity)) - return response(environ, start_response) - -def not_found(environ, start_response): - """Called if no URL matches.""" - resp = NotFound('Not Found') - return resp(environ, start_response) - -def not_authn(environ, start_response): - if "QUERY_STRING" in environ: - query = parse_qs(environ["QUERY_STRING"]) - logger.info("query: %s" % query) - resp = Unauthorized('Unknown user') - return resp(environ, start_response) - -def slo(environ, start_response, user): - """ Expects a HTTP-redirect logout request """ - - query = None - if "QUERY_STRING" in environ: - logger.info("Query string: %s" % environ["QUERY_STRING"]) - query = parse_qs(environ["QUERY_STRING"]) - - if not query: - resp = Unauthorized('Unknown user') - return resp(environ, start_response) - - try: - req_info = IDP.parse_logout_request(query["SAMLRequest"][0], - BINDING_HTTP_REDIRECT) - logger.info("LOGOUT request parsed OK") - logger.info("REQ_INFO: %s" % req_info.message) - except KeyError, exc: - logger.info("logout request error: %s" % (exc,)) - resp = BadRequest('Request parse error') - return resp(environ, start_response) - - # look for the subject - subject = req_info.subject_id() - subject = subject.text.strip() - logger.info("Logout subject: %s" % (subject,)) - - status = None - - # Either HTTP-Post or HTTP-redirect is possible, prefer HTTP-Post. - # Order matters - bindings = [BINDING_HTTP_POST, BINDING_HTTP_REDIRECT] - try: - response = IDP.create_logout_response(req_info.message, - bindings) - binding, destination = IDP.pick_binding("single_logout_service", - bindings, "spsso", response) - - http_args = IDP.apply_binding(binding, "%s" % response, destination, - query["RelayState"], response=True) - - except Exception, exc: - resp = BadRequest('%s' % exc) - return resp(environ, start_response) - - delco = delete_cookie(environ, "pysaml2idp") - if delco: - http_args["headers"].append(delco) - - if binding == BINDING_HTTP_POST: - resp = Response(http_args["data"], headers=http_args["headers"]) - else: - resp = NotFound(http_args["data"], headers=http_args["headers"]) - return resp(environ, start_response) - -def delete_cookie(environ, name): - kaka = environ.get("HTTP_COOKIE", '') - if kaka: - cookie_obj = SimpleCookie(kaka) - morsel = cookie_obj.get(name, None) - cookie = SimpleCookie() - cookie[name] = morsel - cookie[name]["expires"] = \ - _expiration("now", "%a, %d-%b-%Y %H:%M:%S CET") - return tuple(cookie.output().split(": ", 1)) - return None - -# ---------------------------------------------------------------------------- - -# map urls to functions -URLS = [ - (r'whoami$', whoami), - (r'whoami/(.*)$', whoami), - (r'sso$', sso), - (r'sso/(.*)$', sso), - (r'logout$', slo), - (r'logout/(.*)$', slo), -] - -# ---------------------------------------------------------------------------- - -def application(environ, start_response): - """ - The main WSGI application. Dispatch the current request to - the functions from above and store the regular expression - captures in the WSGI environment as `myapp.url_args` so that - the functions from above can access the url placeholders. - - If nothing matches call the `not_found` function. - - :param environ: The HTTP application environment - :param start_response: The application to run when the handling of the - request is done - :return: The response as a list of lines - """ - user = environ.get("REMOTE_USER", "") - kaka = environ.get("HTTP_COOKIE", '') - if not user: - user = environ.get("repoze.who.identity", "") - - path = environ.get('PATH_INFO', '').lstrip('/') - logger.info(" PATH: %s" % path) - logger.info("Cookie: %s" % (kaka,)) - for regex, callback in URLS: - if user: - match = re.search(regex, path) - if match is not None: - try: - environ['myapp.url_args'] = match.groups()[0] - except IndexError: - environ['myapp.url_args'] = path - logger.info("callback: %s" % (callback,)) - return callback(environ, start_response, user) - else: - logger.info("-- No USER --") - return not_authn(environ, start_response) - return not_found(environ, start_response) - -# ---------------------------------------------------------------------------- - -from repoze.who.config import make_middleware_with_config - -APP_WITH_AUTH = make_middleware_with_config(application, {"here":"."}, - './who.ini', log_file="repoze_who.log") - -# ---------------------------------------------------------------------------- - -if __name__ == '__main__': - import sys - from wsgiref.simple_server import make_server - - PORT = 8088 - - IDP = server.Server(sys.argv[1]) - SRV = make_server('localhost', PORT, APP_WITH_AUTH) - print "IdP listening on port: %s" % PORT - SRV.serve_forever() \ No newline at end of file diff --git a/example/idp/idp_conf.py.example b/example/idp/idp_conf.py.example deleted file mode 100644 index 250c1ca..0000000 --- a/example/idp/idp_conf.py.example +++ /dev/null @@ -1,53 +0,0 @@ -from saml2 import BINDING_HTTP_REDIRECT -from saml2.saml import NAME_FORMAT_URI - -BASE = "http://localhost:8088/" - -CONFIG={ - "entityid" : "urn:mace:umu.se:saml:roland:idp", - "description": "My IDP", - "service": { - "idp": { - "name" : "Rolands IdP", - "endpoints" : { - "single_sign_on_service" : [BASE+"sso"], - "single_logout_service" : [(BASE+"logout", - BINDING_HTTP_REDIRECT)], - }, - "policy": { - "default": { - "lifetime": {"minutes":15}, - "attribute_restrictions": None, # means all I have - "name_form": NAME_FORMAT_URI - }, - "urn:mace:umu.se:saml:roland:sp": { - "lifetime": {"minutes": 5}, - } - }, - "subject_data": "./idp.subject.db", - } - }, - "debug" : 1, - "key_file" : "pki/mykey.pem", - "cert_file" : "pki/mycert.pem", - "metadata" : { - "local": ["../sp/sp.xml"], - }, - "organization": { - "display_name": "Rolands Identiteter", - "name": "Rolands Identiteter", - "url": "http://www.example.com", - }, - # This database holds the map between a subjects local identifier and - # the identifier returned to a SP - #"xmlsec_binary": "/usr/local/bin/xmlsec1", - "attribute_map_dir" : "../attributemaps", - "logger": { - "rotating": { - "filename": "idp.log", - "maxBytes": 100000, - "backupCount": 5, - }, - "loglevel": "debug", - } -} diff --git a/example/idp/idp_user.ini b/example/idp/idp_user.ini deleted file mode 100644 index f8cb558..0000000 --- a/example/idp/idp_user.ini +++ /dev/null @@ -1,25 +0,0 @@ -[roland] -surname=Hedberg -givenName=Roland -eduPersonAffiliation=staff -uid=rohe0002 - -[ozzie] -surname=Guillen -givenName=Ozzie -eduPersonAffiliation=affiliate - -[derek] -surname=Jeter -givenName=Derek -eduPersonAffiliation=affiliate - -[ichiro] -surname=Suzuki -givenName=Ischiro -eduPersonAffiliation=affiliate - -[ryan] -surname=Howard -givenName=Ryan -eduPersonAffiliation=affiliate diff --git a/example/idp/passwd b/example/idp/passwd deleted file mode 100644 index d652eaf..0000000 --- a/example/idp/passwd +++ /dev/null @@ -1,5 +0,0 @@ -roland:Jek7qtYXouxmM -ozzie:wT390u9XwBFaU -derek:efNb53YcncbRI -ryan:YlIhvZ6Rdt6fA -ischiro:wgMhJvmkQgMGs diff --git a/example/idp/pki/mycert.pem b/example/idp/pki/mycert.pem deleted file mode 100644 index d4a0873..0000000 --- a/example/idp/pki/mycert.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC8jCCAlugAwIBAgIJAJHg2V5J31I8MA0GCSqGSIb3DQEBBQUAMFoxCzAJBgNV -BAYTAlNFMQ0wCwYDVQQHEwRVbWVhMRgwFgYDVQQKEw9VbWVhIFVuaXZlcnNpdHkx -EDAOBgNVBAsTB0lUIFVuaXQxEDAOBgNVBAMTB1Rlc3QgU1AwHhcNMDkxMDI2MTMz -MTE1WhcNMTAxMDI2MTMzMTE1WjBaMQswCQYDVQQGEwJTRTENMAsGA1UEBxMEVW1l -YTEYMBYGA1UEChMPVW1lYSBVbml2ZXJzaXR5MRAwDgYDVQQLEwdJVCBVbml0MRAw -DgYDVQQDEwdUZXN0IFNQMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkJWP7 -bwOxtH+E15VTaulNzVQ/0cSbM5G7abqeqSNSs0l0veHr6/ROgW96ZeQ57fzVy2MC -FiQRw2fzBs0n7leEmDJyVVtBTavYlhAVXDNa3stgvh43qCfLx+clUlOvtnsoMiiR -mo7qf0BoPKTj7c0uLKpDpEbAHQT4OF1HRYVxMwIDAQABo4G/MIG8MB0GA1UdDgQW -BBQ7RgbMJFDGRBu9o3tDQDuSoBy7JjCBjAYDVR0jBIGEMIGBgBQ7RgbMJFDGRBu9 -o3tDQDuSoBy7JqFepFwwWjELMAkGA1UEBhMCU0UxDTALBgNVBAcTBFVtZWExGDAW -BgNVBAoTD1VtZWEgVW5pdmVyc2l0eTEQMA4GA1UECxMHSVQgVW5pdDEQMA4GA1UE -AxMHVGVzdCBTUIIJAJHg2V5J31I8MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF -BQADgYEAMuRwwXRnsiyWzmRikpwinnhTmbooKm5TINPE7A7gSQ710RxioQePPhZO -zkM27NnHTrCe2rBVg0EGz7QTd1JIwLPvgoj4VTi/fSha/tXrYUaqc9AqU1kWI4WN -+vffBGQ09mo+6CffuFTZYeOhzP/2stAPwCTU4kxEoiy0KpZMANI= ------END CERTIFICATE----- diff --git a/example/idp/pki/mykey.pem b/example/idp/pki/mykey.pem deleted file mode 100644 index d9ec5f8..0000000 --- a/example/idp/pki/mykey.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDkJWP7bwOxtH+E15VTaulNzVQ/0cSbM5G7abqeqSNSs0l0veHr -6/ROgW96ZeQ57fzVy2MCFiQRw2fzBs0n7leEmDJyVVtBTavYlhAVXDNa3stgvh43 -qCfLx+clUlOvtnsoMiiRmo7qf0BoPKTj7c0uLKpDpEbAHQT4OF1HRYVxMwIDAQAB -AoGAbx9rKH91DCw/ZEPhHsVXJ6cYHxGcMoAWvnMMC9WUN+bNo4gNL205DLfsxXA1 -jqXFXZj3+38vSFumGPA6IvXrN+Wyp3+Lz3QGc4K5OdHeBtYlxa6EsrxPgvuxYDUB -vx3xdWPMjy06G/ML+pR9XHnRaPNubXQX3UxGBuLjwNXVmyECQQD2/D84tYoCGWoq -5FhUBxFUy2nnOLKYC/GGxBTX62iLfMQ3fbQcdg2pJsB5rrniyZf7UL+9FOsAO9k1 -8DO7G12DAkEA7Hkdg1KEw4ZfjnnjEa+KqpyLTLRQ91uTVW6kzR+4zY719iUJ/PXE -PxJqm1ot7mJd1LW+bWtjLpxs7jYH19V+kQJBAIEpn2JnxdmdMuFlcy/WVmDy09pg -0z0imdexeXkFmjHAONkQOv3bWv+HzYaVMo8AgCOksfEPHGqN4eUMTfFeuUMCQF+5 -E1JSd/2yCkJhYqKJHae8oMLXByNqRXTCyiFioutK4JPYIHfugJdLfC4QziD+Xp85 -RrGCU+7NUWcIJhqfiJECQAIgUAzfzhdj5AyICaFPaOQ+N8FVMLcTyqeTXP0sIlFk -JStVibemTRCbxdXXM7OVipz1oW3PBVEO3t/VyjiaGGg= ------END RSA PRIVATE KEY----- diff --git a/example/idp/who.ini b/example/idp/who.ini deleted file mode 100644 index 75817f9..0000000 --- a/example/idp/who.ini +++ /dev/null @@ -1,57 +0,0 @@ -[plugin:form] -# identificaion and challenge -use = s2repoze.plugins.formswithhidden:make_plugin -login_form_qs = __do_login -rememberer_name = auth_tkt -#form = %(here)s/login_form.html - -[plugin:auth_tkt] -# identification -use = repoze.who.plugins.auth_tkt:make_plugin -secret = cassiopeja -cookie_name = pysaml2idp -secure = False -include_ip = True -timeout=3600 -reissue_time = 3000 - -[plugin:basicauth] -# identification and challenge -use = repoze.who.plugins.basicauth:make_plugin -realm = 'sample' - -[plugin:htpasswd] -# authentication -use = repoze.who.plugins.htpasswd:make_plugin -filename = %(here)s/passwd -check_fn = repoze.who.plugins.htpasswd:crypt_check - -[plugin:ini] -use = s2repoze.plugins.ini:make_plugin -ini_file = %(here)s/idp_user.ini - -[general] -request_classifier = repoze.who.classifiers:default_request_classifier -challenge_decider = repoze.who.classifiers:default_challenge_decider -remote_user_key = REMOTE_USER - -[identifiers] -# plugin_name;classifier_name:.. or just plugin_name (good for any) -plugins = - form;browser - auth_tkt - basicauth - -[authenticators] -# plugin_name;classifier_name.. or just plugin_name (good for any) -plugins = - htpasswd - -[challengers] -# plugin_name;classifier_name:.. or just plugin_name (good for any) -plugins = - form;browser - basicauth - -[mdproviders] -plugins = ini diff --git a/tests/sp_1_conf.py b/tests/sp_1_conf.py index e39be48..90bf075 100644 --- a/tests/sp_1_conf.py +++ b/tests/sp_1_conf.py @@ -2,47 +2,49 @@ from pathutils import full_path CONFIG = { - "entityid" : "urn:mace:example.com:saml:roland:sp", - "name" : "urn:mace:example.com:saml:roland:sp", + "entityid": "urn:mace:example.com:saml:roland:sp", + "name": "urn:mace:example.com:saml:roland:sp", "description": "My own SP", "service": { "sp": { - "endpoints":{ - "assertion_consumer_service": ["http://lingon.catalogix.se:8087/"], + "endpoints": { + "assertion_consumer_service": [ + "http://lingon.catalogix.se:8087/"], }, "required_attributes": ["surName", "givenName", "mail"], "optional_attributes": ["title"], "idp": ["urn:mace:example.com:saml:roland:idp"], } }, - "debug" : 1, - "key_file" : full_path("test.key"), - "cert_file" : full_path("test.pem"), - "xmlsec_binary" : None, + "debug": 1, + "key_file": full_path("test.key"), + "cert_file": full_path("test.pem"), + "xmlsec_binary": None, "metadata": { "local": [full_path("idp.xml"), full_path("vo_metadata.xml")], }, - "virtual_organization" : { - "urn:mace:example.com:it:tek":{ - "nameid_format" : "urn:oid:1.3.6.1.4.1.1466.115.121.1.15-NameID", + "virtual_organization": { + "urn:mace:example.com:it:tek": { + "nameid_format": "urn:oid:1.3.6.1.4.1.1466.115.121.1.15-NameID", "common_identifier": "umuselin", } }, "subject_data": full_path("subject_data.db"), "accepted_time_diff": 60, - "attribute_map_dir" : full_path("attributemaps"), + "attribute_map_dir": full_path("attributemaps"), "organization": { "name": ("AB Exempel", "se"), "display_name": ("AB Exempel", "se"), "url": "http://www.example.org", }, "contact_person": [{ - "given_name": "Roland", - "sur_name": "Hedberg", - "telephone_number": "+46 70 100 0000", - "email_address": ["tech@eample.com", "tech@example.org"], - "contact_type": "technical" - }, + "given_name": "Roland", + "sur_name": "Hedberg", + "telephone_number": "+46 70 100 0000", + "email_address": ["tech@eample.com", + "tech@example.org"], + "contact_type": "technical" + }, ], "secret": "0123456789", }