@@ -677,11 +677,258 @@ password, it's the same one for each private key.
677
677
Configuration
678
678
+++++++++++++
679
679
680
- **ZzzzzZzz ** All the config options go here..
680
+ The two main classes to use in secure XML-RPC communications are
681
+ :ref: `springpython.remoting.xmlrpc.SSLServer <remoting-secure-xml-config-sslserver >`
682
+ and
683
+ :ref: `springpython.remoting.xmlrpc.SSLClient <remoting-secure-xml-config-sslclient >`
684
+ both of which support a number of options discussed below.
685
+ Keep in mind that those classes are thin wrappers around the base objects found
686
+ in Python's standard library and as such they always accept all the default arguments
687
+ of their super-classes along with those specific to Spring Python's secure XML-RPC
688
+ implementation.
689
+
690
+ .. _remoting-secure-xml-config-sslserver :
691
+
692
+ SSLServer
693
+ >>>>>>>>>
694
+
695
+ SSLServer is a subclass of Python's
696
+ `SimpleXMLRPCServer.SimpleXMLRPCServer <http://docs.python.org/library/simplexmlrpcserver.html#module-SimpleXMLRPCServer >`_
697
+ which accepts arguments related to SSL in addition to those inherited from
698
+ the base class. You expose XML-RPC services by extending SSLServer in your
699
+ own subclass which is required to override one method, *register_functions *.
700
+ *register_functions * may in turn use *self.register_function * for exposing those
701
+ methods that should be accessible via XML-RPC, see
702
+ `Python's documentation <http://docs.python.org/library/simplexmlrpcserver.html#SimpleXMLRPCServer.SimpleXMLRPCServer.register_function >`_
703
+ for details of using *self.register_function *.
704
+
705
+ SSLServer.__init__'s default arguments::
706
+
707
+ class SSLServer(object, SimpleXMLRPCServer):
708
+ def __init__(self, host=None, port=None, keyfile=None, certfile=None,
709
+ ca_certs=None, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_TLSv1,
710
+ do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None, **kwargs):
711
+
712
+ * *host * - interface to listen on, e.g. "localhost",
713
+ * *port * - port to listen on, e.g. 8000,
714
+ * *keyfile * - path to a PEM-encoded private key of the server, e.g. "./server-key.pem",
715
+ * *certfile * - path to a PEM-encoded certificate of the server, e.g. "./server-cert.pem",
716
+ * *ca_certs * - path to a PEM-encoded list (possibly one element long) of certificates
717
+ of Certificate Authorities signing the certificates of clients you deal with,
718
+ e.g. "./ca-chain.pem",
719
+ * *cert_reqs * - whether the client is required to authenticate itself with a certificate,
720
+ see `Python's documentation <http://docs.python.org/library/ssl.html#ssl.wrap_socket >`_
721
+ for supported values,
722
+ * *ssl_version * - the SSL/TLS version to use, see
723
+ `Python's documentation <http://docs.python.org/library/ssl.html#ssl.wrap_socket >`_
724
+ for supported values, note that the same value **must ** be used by the client
725
+ application,
726
+ * *do_handshake_on_connect * - `same as in Python <http://docs.python.org/library/ssl.html#ssl.wrap_socket >`_,
727
+ * *suppress_ragged_eofs * - `same as in Python <http://docs.python.org/library/ssl.html#ssl.wrap_socket >`_,
728
+ * *ciphers * - `same as in Python <http://docs.python.org/library/ssl.html#ssl.wrap_socket >`_,
729
+ the value will be silently ignored if not running Python 2.7 or newer,
730
+ * *\* *kwargs * - an open-ended list of keyword arguments, currently the only
731
+ argument being recognized is *verify_fields * which must be a dictionary
732
+ containing fields and values of the client certificate that must exist when the client's
733
+ connecting. Fields names should be in the format given in `Appendix A of RFC 3280 <http://tools.ietf.org/html/rfc3280 >`_,
734
+ which means using long names instead of short ones (commonName not CN, organizationName not O, etc.),
735
+ for instance, setting verify_fields to:
736
+
737
+ ::
738
+
739
+ {"commonName":"My Client", "localityName":"My Town"}
740
+
741
+ will make sure the client certificate's subject has both commonName and localityName
742
+ set and will also validate their respective values. The connection will not
743
+ be accepted unless the fields and values match.
744
+
745
+ .. _remoting-secure-xml-config-sslserver-sample :
746
+
747
+ Sample SSL XML-RPC server which expects the client to use a certificate whose
748
+ fields must match the configuration. The server exposes one method, *listdir *::
749
+
750
+ # -*- coding: utf-8 -*-
751
+
752
+ # stdlib
753
+ import logging
754
+ import os
755
+ import ssl
756
+
757
+ # Spring Python
758
+ from springpython.remoting.xmlrpc import SSLServer
759
+
760
+ class MySSLServer(SSLServer):
761
+ def __init__(self, *args, **kwargs):
762
+ super(MySSLServer, self).__init__(*args, **kwargs)
763
+
764
+ def _listdir(self, path):
765
+ return os.listdir(path)
766
+
767
+ def register_functions(self):
768
+ self.register_function(self._listdir, "listdir")
769
+
770
+ host = "localhost"
771
+ port = 8000
772
+ keyfile = "./server-key.pem"
773
+ certfile = "./server-cert.pem"
774
+ ca_certs = "./ca-chain.pem"
775
+ verify_fields = {"commonName": "My Client", "organizationName":"My Company",
776
+ "stateOrProvinceName":"My State"}
777
+
778
+ logging.basicConfig(level=logging.ERROR)
779
+
780
+ server = MySSLServer(host, port, keyfile, certfile, ca_certs, cert_reqs=ssl.CERT_REQUIRED,
781
+ verify_fields=verify_fields)
782
+ server.serve_forever()
783
+
784
+ .. _remoting-secure-xml-config-sslclient :
785
+
786
+ SSLClient
787
+ >>>>>>>>>
788
+
789
+ SSLClient extends Python's built-in
790
+ `xmlrpclib.ServerProxy <http://docs.python.org/library/xmlrpclib.html#xmlrpclib.ServerProxy >`_
791
+ class and, unlike :ref: `SSLServer <remoting-secure-xml-config-sslserver >`,
792
+ can be used directly without the need for subclassing. You can simply create
793
+ an instance and start invoking server's methods.
794
+
795
+ SSLClient.__init__’s default arguments::
796
+
797
+ class SSLClient(ServerProxy):
798
+ def __init__(self, uri=None, ca_certs=None, keyfile=None, certfile=None,
799
+ cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLSv1,
800
+ transport=None, encoding=None, verbose=0, allow_none=0, use_datetime=0,
801
+ timeout=socket._GLOBAL_DEFAULT_TIMEOUT, strict=None):
802
+
803
+ * *uri * - address of the XML-RPC server, e.g. "https://localhost:8000/RPC2",
804
+ * *ca_certs * - path to a PEM-encoded list (possibly one element long) containing certificates
805
+ of Certificate Authorities the client is to trust; client will be establishing
806
+ authenticity of the server's certificate against certificates from that file;
807
+ e.g. "./ca-chain.pem",
808
+ * *keyfile * - path to a PAM-encoded private key of the client, e.g. "./client-key.pem",
809
+ * *certfile * - path to a PAM-encoded certificate of the client, e.g. "./client-key.pem",
810
+ * *cert_reqs * - whether a server is required to have a certificate,
811
+ see `Python's documentation <http://docs.python.org/library/ssl.html#ssl.wrap_socket >`_
812
+ for supported values,
813
+ * *ssl_version * - the SSL/TLS version to use, see
814
+ `Python's documentation <http://docs.python.org/library/ssl.html#ssl.wrap_socket >`_
815
+ for supported values, note that the same value **must ** be used by the server,
816
+ * *transport * - `same as in Python <http://docs.python.org/library/xmlrpclib.html#xmlrpclib.ServerProxy >`_,
817
+ * *encoding * - `same as in Python <http://docs.python.org/library/xmlrpclib.html#xmlrpclib.ServerProxy >`_,
818
+ * *verbose * - `same as in Python <http://docs.python.org/library/xmlrpclib.html#xmlrpclib.ServerProxy >`_,
819
+ * *allow_none * - `same as in Python <http://docs.python.org/library/xmlrpclib.html#xmlrpclib.ServerProxy >`_,
820
+ * *use_datetime * - `same as in Python <http://docs.python.org/library/xmlrpclib.html#xmlrpclib.ServerProxy >`_,
821
+
822
+ Sample SSL XML-RPC client which uses a private key and a certificate, can be
823
+ used for invoking the :ref: `server <remoting-secure-xml-config-sslserver-sample >`
824
+ shown in previous chapter::
825
+
826
+ # -*- coding: utf-8 -*-
827
+
828
+ # Spring Python
829
+ from springpython.remoting.xmlrpc import SSLClient
830
+
831
+ server_location = "https://localhost:8000/RPC2"
832
+ keyfile = "./client-key.pem"
833
+ certfile = "./client-cert.pem"
834
+ ca_certs = "./ca-chain.pem"
835
+
836
+ client = SSLClient(server_location, ca_certs, keyfile, certfile)
837
+
838
+ print client.listdir("/home")
681
839
682
840
.. _remoting-secure-xml-rpc-logging :
683
841
684
842
Logging
685
843
+++++++
686
844
687
- **ZzzzzZzz ** Describe loggers used..
845
+ .. _remoting-secure-xml-logging-sslserver :
846
+
847
+ SSLServer
848
+ >>>>>>>>>
849
+
850
+ Your subclass of SSLServer can be configured to use Python's
851
+ standard `logging <http://docs.python.org/library/logging.html >`_ module.
852
+ Currently, logging events are emitted at *DEBUG * and *ERROR * levels.
853
+
854
+ At ERROR level all failed attempts at validating of client certificates will
855
+ be logged giving the exact reason for the failure. Interal errors (should they ever happen)
856
+ are also logged at the ERROR level.
857
+
858
+ When told to run at DEBUG level, in addition to information logged at the ERROR level,
859
+ the server will also log details of each client's certificate received along with
860
+ the IP address of a client application connecting.
861
+
862
+ A sample SSL XML-RPC running with full verbosity turned on::
863
+
864
+ # -*- coding: utf-8 -*-
865
+
866
+ # stdlib
867
+ import logging
868
+ import os
869
+ import ssl
870
+
871
+ # Spring Python
872
+ from springpython.remoting.xmlrpc import SSLServer
873
+
874
+ class MySSLServer(SSLServer):
875
+ def __init__(self, *args, **kwargs):
876
+ super(MySSLServer, self).__init__(*args, **kwargs)
877
+
878
+ def _listdir(self, path):
879
+ return os.listdir(path)
880
+
881
+ def register_functions(self):
882
+ self.register_function(self._listdir, "listdir")
883
+
884
+ host = "localhost"
885
+ port = 8000
886
+ keyfile = "./server-key.pem"
887
+ certfile = "./server-cert.pem"
888
+ ca_certs = "./ca-chain.pem"
889
+ verify_fields = {"commonName": "My Client", "organizationName":"My Company",
890
+ "stateOrProvinceName":"My State"}
891
+
892
+ log_format = "%(asctime)s - %(levelname)s - %(process)d - %(threadName)s - %(name)s - %(message)s"
893
+ formatter = logging.Formatter(log_format)
894
+
895
+ handler = logging.StreamHandler()
896
+ handler.setFormatter(formatter)
897
+
898
+ logger = logging.getLogger("MySSLServer")
899
+
900
+ logger.setLevel(level=logging.DEBUG)
901
+ logger.addHandler(handler)
902
+
903
+
904
+ server = MySSLServer(host, port, keyfile, certfile, ca_certs, cert_reqs=ssl.CERT_REQUIRED,
905
+ verify_fields=verify_fields)
906
+ server.serve_forever()
907
+
908
+ .. _remoting-secure-xml-logging-sslclient :
909
+
910
+ SSLClient
911
+ >>>>>>>>>
912
+
913
+ Although SSLClient does define a self.logger object it isn't currently used
914
+ internally in any situation (subject to change without notice so you shouldn't
915
+ rely on the current status). On the other hand, as a subclass of
916
+ `xmlrpclib.ServerProxy <http://docs.python.org/library/xmlrpclib.html#xmlrpclib.ServerProxy >`_,
917
+ the client may be configured to run in a *verbose * mode which means all HTTP traffic
918
+ will be printed onto *standard output *.
919
+
920
+ A sample SSL XML-RPC client configured to use the verbose mode::
921
+
922
+ # -*- coding: utf-8 -*-
923
+
924
+ # Spring Python
925
+ from springpython.remoting.xmlrpc import SSLClient
926
+
927
+ server_location = "https://localhost:8000/RPC2"
928
+ keyfile = "./client-key.pem"
929
+ certfile = "./client-cert.pem"
930
+ ca_certs = "./ca-chain.pem"
931
+
932
+ client = SSLClient(server_location, ca_certs, keyfile, certfile, verbose=1)
933
+
934
+ print client.listdir("/home")
0 commit comments