11#!/usr/bin/env python
22from __future__ import print_function
3- import logging
4- import re
3+
54import argparse
5+ import importlib
6+ import logging
67import os
8+ import re
9+ import sys
710
8- from six .moves .http_cookies import SimpleCookie
911import six
10-
11- from saml2 .extension .pefim import SPCertEnc
12- from saml2 .metadata import create_metadata_string
13- import service_conf
14-
12+ from six .moves .http_cookies import SimpleCookie
1513from six .moves .urllib .parse import parse_qs
16- import sys
1714
15+ import saml2 .xmldsig as ds
16+ from saml2 import BINDING_HTTP_ARTIFACT
17+ from saml2 import BINDING_HTTP_POST
1818from saml2 import BINDING_HTTP_REDIRECT , element_to_extension_element
1919from saml2 import BINDING_SOAP
20- from saml2 import time_util
2120from saml2 import ecp
22- from saml2 import BINDING_HTTP_ARTIFACT
23- from saml2 import BINDING_HTTP_POST
21+ from saml2 import time_util
2422from saml2 .client import Saml2Client
2523from saml2 .ecp_client import PAOS_HEADER_INFO
26- from saml2 .httputil import geturl , make_cookie , parse_cookie
27- from saml2 .httputil import get_post
28- from saml2 .httputil import Response
24+ from saml2 .extension .pefim import SPCertEnc
2925from saml2 .httputil import BadRequest
30- from saml2 .httputil import ServiceError
31- from saml2 .httputil import SeeOther
32- from saml2 .httputil import Unauthorized
3326from saml2 .httputil import NotFound
34- from saml2 .httputil import Redirect
3527from 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
3636from saml2 .response import StatusError
3737from saml2 .response import VerificationError
3838from saml2 .s_utils import UnknownPrincipal
39- from saml2 .s_utils import decode_base64_and_inflate
4039from saml2 .s_utils import UnsupportedBinding
41- from saml2 .s_utils import sid
40+ from saml2 .s_utils import decode_base64_and_inflate
4241from saml2 .s_utils import rndstr
43- #from srtest import exception_trace
42+ from saml2 .s_utils import sid
43+ from saml2 .saml import NAMEID_FORMAT_PERSISTENT
4444from saml2 .samlp import Extensions
45- from saml2 import xmldsig as ds
46- import saml2 .xmldsig as ds
4745
4846logger = logging .getLogger ("" )
4947hdlr = logging .FileHandler ('spx.log' )
5452logger .addHandler (hdlr )
5553logger .setLevel (logging .INFO )
5654
57-
5855SP = None
5956SEED = ""
6057POLICY = None
@@ -139,7 +136,7 @@ class ECPResponse(object):
139136 def __init__ (self , content ):
140137 self .content = content
141138
142- #noinspection PyUnusedLocal
139+ # noinspection PyUnusedLocal
143140 def __call__ (self , environ , start_response ):
144141 start_response ('%s %s' % (self .code , self .title ),
145142 [('Content-Type' , "text/xml" )])
@@ -351,7 +348,7 @@ def do(self, response, binding, relay_state="", mtype="response"):
351348 :param response: The SAML response, transport encoded
352349 :param binding: Which binding the query came in over
353350 """
354- #tmp_outstanding_queries = dict(self.outstanding_queries)
351+ # tmp_outstanding_queries = dict(self.outstanding_queries)
355352 if not response :
356353 logger .info ("Missing Response" )
357354 resp = Unauthorized ('Unknown user' )
@@ -405,6 +402,7 @@ def verify_attributes(self, ava):
405402
406403 return res
407404
405+
408406# -----------------------------------------------------------------------------
409407# REQUESTERS
410408# -----------------------------------------------------------------------------
@@ -554,7 +552,7 @@ def redirect_to_auth(self, _cli, entity_id, came_from, sigalg=""):
554552 "single_sign_on_service" , self .bindings , "idpsso" ,
555553 entity_id = entity_id )
556554 logger .debug ("binding: %s, destination: %s" , _binding ,
557- destination )
555+ destination )
558556 # Binding here is the response binding that is which binding the
559557 # IDP should use to return the response.
560558 acs = _cli .config .getattr ("endpoints" , "sp" )[
@@ -565,19 +563,20 @@ def redirect_to_auth(self, _cli, entity_id, came_from, sigalg=""):
565563 extensions = None
566564 cert = None
567565 if _cli .config .generate_cert_func is not None :
568- cert_str , req_key_str = _cli .config .generate_cert_func ()
569- cert = {
570- "cert" : cert_str ,
571- "key" : req_key_str
572- }
573- spcertenc = SPCertEnc (x509_data = ds .X509Data (
574- x509_certificate = ds .X509Certificate (text = cert_str )))
575- extensions = Extensions (extension_elements = [
576- 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 )])
577575
578576 req_id , req = _cli .create_authn_request (destination ,
579577 binding = return_binding ,
580- extensions = extensions )
578+ extensions = extensions ,
579+ nameid_format = NAMEID_FORMAT_PERSISTENT )
581580 _rstate = rndstr ()
582581 self .cache .relay_state [_rstate ] = came_from
583582 ht_args = _cli .apply_binding (_binding , "%s" % req , destination ,
@@ -636,7 +635,7 @@ def do(self, message, binding, relay_state="", mtype="response"):
636635 try :
637636 txt = decode_base64_and_inflate (message )
638637 is_logout_request = 'LogoutRequest' in txt .split ('>' , 1 )[0 ]
639- except : # TODO: parse the XML correctly
638+ except : # TODO: parse the XML correctly
640639 is_logout_request = False
641640
642641 if is_logout_request :
@@ -646,10 +645,11 @@ def do(self, message, binding, relay_state="", mtype="response"):
646645
647646 return finish_logout (self .environ , self .start_response )
648647
648+
649649# ----------------------------------------------------------------------------
650650
651651
652- #noinspection PyUnusedLocal
652+ # noinspection PyUnusedLocal
653653def not_found (environ , start_response ):
654654 """Called if no URL matches."""
655655 resp = NotFound ('Not Found' )
@@ -659,7 +659,7 @@ def not_found(environ, start_response):
659659# ----------------------------------------------------------------------------
660660
661661
662- #noinspection PyUnusedLocal
662+ # noinspection PyUnusedLocal
663663def main (environ , start_response , sp ):
664664 user = CACHE .get_user (environ )
665665
@@ -687,10 +687,11 @@ def disco(environ, start_response, _sp):
687687 resp .headers .append (kaka )
688688 return resp (environ , start_response )
689689
690+
690691# ----------------------------------------------------------------------------
691692
692693
693- #noinspection PyUnusedLocal
694+ # noinspection PyUnusedLocal
694695def logout (environ , start_response , sp ):
695696 user = CACHE .get_user (environ )
696697
@@ -737,10 +738,11 @@ def finish_logout(environ, start_response):
737738 cookie = CACHE .delete_cookie (environ )
738739
739740 resp = Response ('You are now logged out of this service' , headers = [
740- cookie ,
741+ cookie ,
741742 ])
742743 return resp (environ , start_response )
743744
745+
744746# ----------------------------------------------------------------------------
745747
746748# map urls to functions
@@ -768,16 +770,17 @@ def add_urls():
768770 urls .append (("%s/redirect$" % base , (SLO , "redirect" , SP )))
769771 urls .append (("%s/redirect/(.*)$" % base , (SLO , "redirect" , SP )))
770772
773+
771774# ----------------------------------------------------------------------------
772775
773776def metadata (environ , start_response ):
774777 try :
775778 path = _args .path
776779 if path is None or len (path ) == 0 :
777- path = os .path .dirname (os .path .abspath ( __file__ ))
780+ path = os .path .dirname (os .path .abspath (__file__ ))
778781 if path [- 1 ] != "/" :
779782 path += "/"
780- metadata = create_metadata_string (path + "sp_conf.py" , None ,
783+ metadata = create_metadata_string (path + "sp_conf.py" , None ,
781784 _args .valid , _args .cert , _args .keyfile ,
782785 _args .id , _args .name , _args .sign )
783786 start_response ('200 OK' , [('Content-Type' , "text/xml" )])
@@ -786,6 +789,7 @@ def metadata(environ, start_response):
786789 logger .error ("An error occured while creating metadata: %s" , ex .message )
787790 return not_found (environ , start_response )
788791
792+
789793def application (environ , start_response ):
790794 """
791795 The main WSGI application. Dispatch the current request to
@@ -824,23 +828,12 @@ def application(environ, start_response):
824828 resp = BadRequest ("%s" % err )
825829 return resp (environ , start_response )
826830 except Exception as err :
827- #_err = exception_trace("RUN", err)
828- #logging.error(exception_trace("RUN", _err))
831+ # _err = exception_trace("RUN", err)
832+ # logging.error(exception_trace("RUN", _err))
829833 print (err , file = sys .stderr )
830834 resp = ServiceError ("%s" % err )
831835 return resp (environ , start_response )
832836
833- # ----------------------------------------------------------------------------
834-
835- HOST = service_conf .HOST
836- PORT = service_conf .PORT
837- # ------- HTTPS -------
838- # These should point to relevant files
839- SERVER_CERT = service_conf .SERVER_CERT
840- SERVER_KEY = service_conf .SERVER_KEY
841- # This is of course the certificate chain for the CA that signed
842- # your cert and all the way up to the top
843- CERT_CHAIN = service_conf .CERT_CHAIN
844837
845838if __name__ == '__main__' :
846839 from cherrypy import wsgiserver
@@ -866,7 +859,8 @@ def application(environ, start_response):
866859 _parser .add_argument ('-n' , dest = 'name' )
867860 _parser .add_argument ('-S' , dest = 'sign' , action = 'store_true' ,
868861 help = "sign the metadata" )
869-
862+ _parser .add_argument ('-C' , dest = 'service_conf_module' ,
863+ help = "service config module" )
870864
871865 ARGS = {}
872866 _args = _parser .parse_args ()
@@ -882,6 +876,21 @@ def application(environ, start_response):
882876 else :
883877 SEED = "SnabbtInspel"
884878
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+
885894 SP = Saml2Client (config_file = "%s" % CNFBASE )
886895
887896 POLICY = service_conf .POLICY
@@ -904,6 +913,7 @@ def application(environ, start_response):
904913 _https = ""
905914 if service_conf .HTTPS :
906915 from cherrypy .wsgiserver import ssl_pyopenssl
916+
907917 SRV .ssl_adapter = ssl_pyopenssl .pyOpenSSLAdapter (SERVER_CERT ,
908918 SERVER_KEY , CERT_CHAIN )
909919 _https = " using SSL/TLS"
0 commit comments