1
1
#!/usr/bin/env python
2
2
from __future__ import print_function
3
- import logging
4
- import re
3
+
5
4
import argparse
5
+ import importlib
6
+ import logging
6
7
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
16
10
11
+ import six
12
+ from six .moves .http_cookies import SimpleCookie
17
13
from six .moves .urllib .parse import parse_qs
18
- import sys
19
14
15
+ import saml2 .xmldsig as ds
16
+ from saml2 import BINDING_HTTP_ARTIFACT
17
+ from saml2 import BINDING_HTTP_POST
20
18
from saml2 import BINDING_HTTP_REDIRECT , element_to_extension_element
21
19
from saml2 import BINDING_SOAP
22
- from saml2 import time_util
23
20
from saml2 import ecp
24
- from saml2 import BINDING_HTTP_ARTIFACT
25
- from saml2 import BINDING_HTTP_POST
21
+ from saml2 import time_util
26
22
from saml2 .client import Saml2Client
27
23
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
31
25
from saml2 .httputil import BadRequest
32
- from saml2 .httputil import ServiceError
33
- from saml2 .httputil import SeeOther
34
- from saml2 .httputil import Unauthorized
35
26
from saml2 .httputil import NotFound
36
- from saml2 .httputil import Redirect
37
27
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
38
36
from saml2 .response import StatusError
39
37
from saml2 .response import VerificationError
40
38
from saml2 .s_utils import UnknownPrincipal
41
- from saml2 .s_utils import decode_base64_and_inflate
42
39
from saml2 .s_utils import UnsupportedBinding
43
- from saml2 .s_utils import sid
40
+ from saml2 .s_utils import decode_base64_and_inflate
44
41
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
46
44
from saml2 .samlp import Extensions
47
- from saml2 import xmldsig as ds
48
- import saml2 .xmldsig as ds
49
45
50
46
logger = logging .getLogger ("" )
51
47
hdlr = logging .FileHandler ('spx.log' )
56
52
logger .addHandler (hdlr )
57
53
logger .setLevel (logging .INFO )
58
54
59
-
60
55
SP = None
61
56
SEED = ""
62
57
POLICY = None
@@ -141,7 +136,7 @@ class ECPResponse(object):
141
136
def __init__ (self , content ):
142
137
self .content = content
143
138
144
- #noinspection PyUnusedLocal
139
+ # noinspection PyUnusedLocal
145
140
def __call__ (self , environ , start_response ):
146
141
start_response ('%s %s' % (self .code , self .title ),
147
142
[('Content-Type' , "text/xml" )])
@@ -172,7 +167,6 @@ def __init__(self):
172
167
173
168
def get_user (self , environ ):
174
169
cookie = environ .get ("HTTP_COOKIE" , '' )
175
- cookie = cookie .decode ("UTF-8" )
176
170
logger .debug ("Cookie: %s" , cookie )
177
171
if cookie :
178
172
cookie_obj = SimpleCookie (cookie )
@@ -354,7 +348,7 @@ def do(self, response, binding, relay_state="", mtype="response"):
354
348
:param response: The SAML response, transport encoded
355
349
:param binding: Which binding the query came in over
356
350
"""
357
- #tmp_outstanding_queries = dict(self.outstanding_queries)
351
+ # tmp_outstanding_queries = dict(self.outstanding_queries)
358
352
if not response :
359
353
logger .info ("Missing Response" )
360
354
resp = Unauthorized ('Unknown user' )
@@ -408,6 +402,7 @@ def verify_attributes(self, ava):
408
402
409
403
return res
410
404
405
+
411
406
# -----------------------------------------------------------------------------
412
407
# REQUESTERS
413
408
# -----------------------------------------------------------------------------
@@ -557,7 +552,7 @@ def redirect_to_auth(self, _cli, entity_id, came_from, sigalg=""):
557
552
"single_sign_on_service" , self .bindings , "idpsso" ,
558
553
entity_id = entity_id )
559
554
logger .debug ("binding: %s, destination: %s" , _binding ,
560
- destination )
555
+ destination )
561
556
# Binding here is the response binding that is which binding the
562
557
# IDP should use to return the response.
563
558
acs = _cli .config .getattr ("endpoints" , "sp" )[
@@ -568,19 +563,20 @@ def redirect_to_auth(self, _cli, entity_id, came_from, sigalg=""):
568
563
extensions = None
569
564
cert = None
570
565
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 )])
580
575
581
576
req_id , req = _cli .create_authn_request (destination ,
582
577
binding = return_binding ,
583
- extensions = extensions )
578
+ extensions = extensions ,
579
+ nameid_format = NAMEID_FORMAT_PERSISTENT )
584
580
_rstate = rndstr ()
585
581
self .cache .relay_state [_rstate ] = came_from
586
582
ht_args = _cli .apply_binding (_binding , "%s" % req , destination ,
@@ -639,7 +635,7 @@ def do(self, message, binding, relay_state="", mtype="response"):
639
635
try :
640
636
txt = decode_base64_and_inflate (message )
641
637
is_logout_request = 'LogoutRequest' in txt .split ('>' , 1 )[0 ]
642
- except : # TODO: parse the XML correctly
638
+ except : # TODO: parse the XML correctly
643
639
is_logout_request = False
644
640
645
641
if is_logout_request :
@@ -649,10 +645,11 @@ def do(self, message, binding, relay_state="", mtype="response"):
649
645
650
646
return finish_logout (self .environ , self .start_response )
651
647
648
+
652
649
# ----------------------------------------------------------------------------
653
650
654
651
655
- #noinspection PyUnusedLocal
652
+ # noinspection PyUnusedLocal
656
653
def not_found (environ , start_response ):
657
654
"""Called if no URL matches."""
658
655
resp = NotFound ('Not Found' )
@@ -662,7 +659,7 @@ def not_found(environ, start_response):
662
659
# ----------------------------------------------------------------------------
663
660
664
661
665
- #noinspection PyUnusedLocal
662
+ # noinspection PyUnusedLocal
666
663
def main (environ , start_response , sp ):
667
664
user = CACHE .get_user (environ )
668
665
@@ -690,10 +687,11 @@ def disco(environ, start_response, _sp):
690
687
resp .headers .append (kaka )
691
688
return resp (environ , start_response )
692
689
690
+
693
691
# ----------------------------------------------------------------------------
694
692
695
693
696
- #noinspection PyUnusedLocal
694
+ # noinspection PyUnusedLocal
697
695
def logout (environ , start_response , sp ):
698
696
user = CACHE .get_user (environ )
699
697
@@ -740,10 +738,11 @@ def finish_logout(environ, start_response):
740
738
cookie = CACHE .delete_cookie (environ )
741
739
742
740
resp = Response ('You are now logged out of this service' , headers = [
743
- cookie ,
741
+ cookie ,
744
742
])
745
743
return resp (environ , start_response )
746
744
745
+
747
746
# ----------------------------------------------------------------------------
748
747
749
748
# map urls to functions
@@ -771,16 +770,17 @@ def add_urls():
771
770
urls .append (("%s/redirect$" % base , (SLO , "redirect" , SP )))
772
771
urls .append (("%s/redirect/(.*)$" % base , (SLO , "redirect" , SP )))
773
772
773
+
774
774
# ----------------------------------------------------------------------------
775
775
776
776
def metadata (environ , start_response ):
777
777
try :
778
778
path = _args .path
779
779
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__ ))
781
781
if path [- 1 ] != "/" :
782
782
path += "/"
783
- metadata = create_metadata_string (path + "sp_conf.py" , None ,
783
+ metadata = create_metadata_string (path + "sp_conf.py" , None ,
784
784
_args .valid , _args .cert , _args .keyfile ,
785
785
_args .id , _args .name , _args .sign )
786
786
start_response ('200 OK' , [('Content-Type' , "text/xml" )])
@@ -789,6 +789,7 @@ def metadata(environ, start_response):
789
789
logger .error ("An error occured while creating metadata: %s" , ex .message )
790
790
return not_found (environ , start_response )
791
791
792
+
792
793
def application (environ , start_response ):
793
794
"""
794
795
The main WSGI application. Dispatch the current request to
@@ -827,27 +828,15 @@ def application(environ, start_response):
827
828
resp = BadRequest ("%s" % err )
828
829
return resp (environ , start_response )
829
830
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))
832
833
print (err , file = sys .stderr )
833
834
resp = ServiceError ("%s" % err )
834
835
return resp (environ , start_response )
835
836
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
847
837
848
838
if __name__ == '__main__' :
849
839
from cherrypy import wsgiserver
850
- from cherrypy .wsgiserver import ssl_pyopenssl
851
840
852
841
_parser = argparse .ArgumentParser ()
853
842
_parser .add_argument ('-d' , dest = 'debug' , action = 'store_true' ,
@@ -870,7 +859,8 @@ def application(environ, start_response):
870
859
_parser .add_argument ('-n' , dest = 'name' )
871
860
_parser .add_argument ('-S' , dest = 'sign' , action = 'store_true' ,
872
861
help = "sign the metadata" )
873
-
862
+ _parser .add_argument ('-C' , dest = 'service_conf_module' ,
863
+ help = "service config module" )
874
864
875
865
ARGS = {}
876
866
_args = _parser .parse_args ()
@@ -886,6 +876,21 @@ def application(environ, start_response):
886
876
else :
887
877
SEED = "SnabbtInspel"
888
878
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
+
889
894
SP = Saml2Client (config_file = "%s" % CNFBASE )
890
895
891
896
POLICY = service_conf .POLICY
@@ -907,6 +912,8 @@ def application(environ, start_response):
907
912
908
913
_https = ""
909
914
if service_conf .HTTPS :
915
+ from cherrypy .wsgiserver import ssl_pyopenssl
916
+
910
917
SRV .ssl_adapter = ssl_pyopenssl .pyOpenSSLAdapter (SERVER_CERT ,
911
918
SERVER_KEY , CERT_CHAIN )
912
919
_https = " using SSL/TLS"
0 commit comments