mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Use OpenSSL for SSL instead of the built-in python version.
This commit is contained in:
@@ -374,6 +374,9 @@ def main():
|
|||||||
print "Caching of users/groups will not be available after reboot"
|
print "Caching of users/groups will not be available after reboot"
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Get the CA certificate
|
||||||
|
run(["/usr/bin/wget", "-O", "/etc/ipa/ca.crt", "http://%s/ipa/config/ca.crt" % cli_server])
|
||||||
|
|
||||||
print "Client configuration complete."
|
print "Client configuration complete."
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ Requires: krb5-libs
|
|||||||
Requires: authconfig
|
Requires: authconfig
|
||||||
Requires: pam_krb5
|
Requires: pam_krb5
|
||||||
Requires: nss_ldap
|
Requires: nss_ldap
|
||||||
|
Requires: wget
|
||||||
|
|
||||||
%description client
|
%description client
|
||||||
IPA is an integrated solution to provide centrally managed Identity (machine,
|
IPA is an integrated solution to provide centrally managed Identity (machine,
|
||||||
@@ -153,6 +154,7 @@ Requires: python-kerberos >= 1.1-3
|
|||||||
%endif
|
%endif
|
||||||
Requires: authconfig
|
Requires: authconfig
|
||||||
Requires: gnupg
|
Requires: gnupg
|
||||||
|
Requires: pyOpenSSL
|
||||||
|
|
||||||
%description python
|
%description python
|
||||||
IPA is an integrated solution to provide centrally managed Identity (machine,
|
IPA is an integrated solution to provide centrally managed Identity (machine,
|
||||||
|
|||||||
130
ipalib/rpc.py
130
ipalib/rpc.py
@@ -33,12 +33,15 @@ Also see the `ipaserver.rpcserver` module.
|
|||||||
from types import NoneType
|
from types import NoneType
|
||||||
import threading
|
import threading
|
||||||
import socket
|
import socket
|
||||||
from xmlrpclib import Binary, Fault, dumps, loads, ServerProxy, SafeTransport
|
import os
|
||||||
|
from xmlrpclib import Binary, Fault, dumps, loads, ServerProxy, Transport
|
||||||
import kerberos
|
import kerberos
|
||||||
from ipalib.backend import Connectible
|
from ipalib.backend import Connectible
|
||||||
from ipalib.errors2 import public_errors, PublicError, UnknownError, NetworkError
|
from ipalib.errors2 import public_errors, PublicError, UnknownError, NetworkError
|
||||||
from ipalib import errors2
|
from ipalib import errors2
|
||||||
from ipalib.request import context
|
from ipalib.request import context
|
||||||
|
from OpenSSL import SSL
|
||||||
|
import httplib
|
||||||
|
|
||||||
|
|
||||||
def xml_wrap(value):
|
def xml_wrap(value):
|
||||||
@@ -175,13 +178,134 @@ def xml_loads(data, encoding='UTF-8'):
|
|||||||
raise decode_fault(e)
|
raise decode_fault(e)
|
||||||
|
|
||||||
|
|
||||||
class KerbTransport(SafeTransport):
|
class SSLTransport(Transport):
|
||||||
|
"""Handles an HTTPS transaction to an XML-RPC server."""
|
||||||
|
|
||||||
|
def make_connection(self, host):
|
||||||
|
host, extra_headers, x509 = self.get_host_info(host)
|
||||||
|
return SSLSocket(host, None, **(x509 or {}))
|
||||||
|
|
||||||
|
|
||||||
|
class SSLFile(httplib.SSLFile):
|
||||||
|
"""
|
||||||
|
Override the _read method so we can handle PyOpenSSL errors
|
||||||
|
gracefully.
|
||||||
|
"""
|
||||||
|
def _read(self):
|
||||||
|
buf = ''
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
buf = self._ssl.read(self._bufsize)
|
||||||
|
except SSL.ZeroReturnError:
|
||||||
|
# Nothing more to be read
|
||||||
|
break
|
||||||
|
except SSL.SysCallError, e:
|
||||||
|
print "SSL exception", e.args
|
||||||
|
break
|
||||||
|
except SSL.WantWriteError:
|
||||||
|
break
|
||||||
|
except SSL.WantReadError:
|
||||||
|
break
|
||||||
|
except socket.error, err:
|
||||||
|
if err[0] == errno.EINTR:
|
||||||
|
continue
|
||||||
|
if err[0] == errno.EBADF:
|
||||||
|
# XXX socket was closed?
|
||||||
|
break
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return buf
|
||||||
|
|
||||||
|
|
||||||
|
class FakeSocket(httplib.FakeSocket):
|
||||||
|
"""
|
||||||
|
Override this class so we can end up using our own SSLFile
|
||||||
|
implementation.
|
||||||
|
"""
|
||||||
|
def makefile(self, mode, bufsize=None):
|
||||||
|
if mode != 'r' and mode != 'rb':
|
||||||
|
raise httplib.UnimplementedFileMode()
|
||||||
|
return SSLFile(self._shared, self._ssl, bufsize)
|
||||||
|
|
||||||
|
|
||||||
|
class SSLConnection(httplib.HTTPConnection):
|
||||||
|
"""
|
||||||
|
Use OpenSSL as the SSL provider instead of the built-in python SSL
|
||||||
|
support. The built-in SSL client doesn't do CA validation.
|
||||||
|
|
||||||
|
By default we will attempt to load the ca-bundle.crt and our own
|
||||||
|
IPA CA for validation purposes. To add an additional CA to verify
|
||||||
|
against set the x509['ca_file'] to the path of the CA PEM file in
|
||||||
|
KerbTransport.get_host_info
|
||||||
|
"""
|
||||||
|
default_port = httplib.HTTPSConnection.default_port
|
||||||
|
|
||||||
|
def verify_callback(self, conn, cert, errnum, depth, ok):
|
||||||
|
"""
|
||||||
|
Verify callback. If we get here then the certificate is ok.
|
||||||
|
"""
|
||||||
|
return ok
|
||||||
|
|
||||||
|
def __init__(self, host, port=None, key_file=None, cert_file=None,
|
||||||
|
ca_file=None, strict=None):
|
||||||
|
httplib.HTTPConnection.__init__(self, host, port, strict)
|
||||||
|
self.key_file = key_file
|
||||||
|
self.cert_file = cert_file
|
||||||
|
self.ca_file = ca_file
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
ctx = SSL.Context(SSL.SSLv23_METHOD)
|
||||||
|
ctx.set_verify(SSL.VERIFY_PEER, self.verify_callback)
|
||||||
|
if self.key_file:
|
||||||
|
ctx.use_privatekey_file (self.key_file)
|
||||||
|
if self.cert_file:
|
||||||
|
ctx.use_certificate_file(self.cert_file)
|
||||||
|
if os.path.exists("/etc/pki/tls/certs/ca-bundle.crt"):
|
||||||
|
ctx.load_verify_locations("/etc/pki/tls/certs/ca-bundle.crt")
|
||||||
|
if os.path.exists("/etc/ipa/ca.crt"):
|
||||||
|
ctx.load_verify_locations("/etc/ipa/ca.crt")
|
||||||
|
if self.ca_file is not None and os.path.exists(self.ca_file):
|
||||||
|
ctx.load_verify_locations(self.ca_file)
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
ssl = SSL.Connection(ctx, sock)
|
||||||
|
ssl.connect((self.host, self.port))
|
||||||
|
ssl.do_handshake()
|
||||||
|
self.sock = FakeSocket(sock, ssl)
|
||||||
|
|
||||||
|
|
||||||
|
class SSLSocket(httplib.HTTP):
|
||||||
|
"""
|
||||||
|
This is more or less equivalent to the httplib.HTTPS class, we juse
|
||||||
|
use our own connection provider.
|
||||||
|
"""
|
||||||
|
_connection_class = SSLConnection
|
||||||
|
|
||||||
|
def __init__(self, host='', port=None, key_file=None, cert_file=None,
|
||||||
|
ca_file=None, strict=None):
|
||||||
|
# provide a default host, pass the X509 cert info
|
||||||
|
|
||||||
|
# urf. compensate for bad input.
|
||||||
|
if port == 0:
|
||||||
|
port = None
|
||||||
|
self._setup(self._connection_class(host, port, key_file,
|
||||||
|
cert_file, ca_file, strict))
|
||||||
|
|
||||||
|
# we never actually use these for anything, but we keep them
|
||||||
|
# here for compatibility with post-1.5.2 CVS.
|
||||||
|
self.key_file = key_file
|
||||||
|
self.cert_file = cert_file
|
||||||
|
self.ca_file = ca_file
|
||||||
|
|
||||||
|
|
||||||
|
class KerbTransport(SSLTransport):
|
||||||
"""
|
"""
|
||||||
Handles Kerberos Negotiation authentication to an XML-RPC server.
|
Handles Kerberos Negotiation authentication to an XML-RPC server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_host_info(self, host):
|
def get_host_info(self, host):
|
||||||
(host, extra_headers, x509) = SafeTransport.get_host_info(self, host)
|
(host, extra_headers, x509) = SSLTransport.get_host_info(self, host)
|
||||||
|
|
||||||
# Set the remote host principal
|
# Set the remote host principal
|
||||||
service = "HTTP@" + host.split(':')[0]
|
service = "HTTP@" + host.split(':')[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user