Issue #263 resolved

mercurial push gives error when configured with SSL

Matthias Lang
created an issue

Hi, I am very happy with scm-manager running on ubuntu 12.04. I am able to configure mercurial repositories and to work with them with the http protocol.

I have tried to configure SSL as described in https://bitbucket.org/sdorra/scm-manager/wiki/scm-server-ssl but I get here into trouble.

After I have configured SSL I am able to clone and pull from repositories, but I am not able to push to repositories. I have switched back to blank http where all works fine meanwhile. So it must have todo with the SSL configuration.

When I try to pull I get the following message from the mercurial client:

abort: remote error:
Mercurial/Python process ends with return code 1

the scm-manager log file says:

13:08:50.427 [qtp1938822199-22] INFO  sonia.scm.repository.HgHookManager - use https://solaris:8181/scm/hook/hg/ for mercurial hooks
13:09:56.411 [qtp1938822199-22] WARN  sonia.scm.web.HgCGIExceptionHandler - Mercurial/Python process ends with return code 1

13:09:56.414 [Thread-17] WARN  sonia.scm.web.cgi.DefaultCGIExecutor - Traceback (most recent call last):
  File "/home/scmmanager/.scm/lib/python/hgweb.py", line 42, in <module>
    wsgicgi.launch(application)
  File "/usr/lib/python2.7/dist-packages/mercurial/hgweb/wsgicgi.py", line 76, in launch
    content = application(environ, start_response)
  File "/usr/lib/python2.7/dist-packages/mercurial/hgweb/hgweb_mod.py", line 91, in __call__
    return self.run_wsgi(req)
  File "/usr/lib/python2.7/dist-packages/mercurial/hgweb/hgweb_mod.py", line 127, in run_wsgi
    return protocol.call(self.repo, req, cmd)
  File "/usr/lib/python2.7/dist-packages/mercurial/hgweb/protocol.py", line 76, in call
    rsp = wireproto.dispatch(repo, p, cmd)
  File "/usr/lib/python2.7/dist-packages/mercurial/wireproto.py", line 344, in dispatch
    return func(repo, proto, *args)
  File "/usr/lib/python2.7/dist-packages/mercurial/wireproto.py", line 578, in unbundle
    lock=lock)
  File "/usr/lib/python2.7/dist-packages/mercurial/localrepo.py", line 1944, in addchangegroup
    url=url, pending=p)
  File "/usr/lib/python2.7/dist-packages/mercurial/localrepo.py", line 239, in hook
    return hook.hook(self.ui, self, name, throw, **args)
  File "/usr/lib/python2.7/dist-packages/mercurial/hook.py", line 165, in hook
    r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
  File "/usr/lib/python2.7/dist-packages/mercurial/hook.py", line 75, in _pythonhook
    r = obj(ui=ui, repo=repo, hooktype=name, **args)
  File "/home/scmmanager/.scm/lib/python/scmhooks.py", line 67, in callback
    abort = callHookUrl(ui, repo, hooktype, node)
  File "/home/scmmanager/.scm/lib/python/scmhooks.py", line 51, in callHookUrl
    conn = urllib2.urlopen(url, data);
  File "/usr/lib/python2.7/urllib2.py", line 126, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 400, in open
    response = self._open(req, data)
  File "/usr/lib/python2.7/urllib2.py", line 418, in _open
    '_open', req)
  File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 1215, in https_open
    return self.do_open(httplib.HTTPSConnection, req)
  File "/usr/lib/python2.7/urllib2.py", line 1177, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error [Errno 6] _ssl.c:504: TLS/SSL connection has been closed>
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/apport_python_hook.py", line 66, in apport_excepthook
    from apport.fileutils import likely_packaged, get_recent_crashes
  File "/usr/lib/python2.7/dist-packages/mercurial/demandimport.py", line 95, in _demandimport
    return _import(name, globals, locals, fromlist, level)
  File "/usr/lib/python2.7/dist-packages/apport/__init__.py", line 1, in <module>
    from apport.report import Report
  File "/usr/lib/python2.7/dist-packages/mercurial/demandimport.py", line 114, in _demandimport
    mod = _origimport(name, globals, locals)
  File "/usr/lib/python2.7/dist-packages/apport/report.py", line 155, in <module>
    class Report(problem_report.ProblemReport):
  File "/usr/lib/python2.7/dist-packages/mercurial/demandimport.py", line 86, in __getattribute__
    self._load()
  File "/usr/lib/python2.7/dist-packages/mercurial/demandimport.py", line 58, in _load
    mod = _origimport(head, globals, locals)
  File "/usr/lib/python2.7/dist-packages/problem_report.py", line 93, in <module>
    class ProblemReport(UserDict):
TypeError: Error when calling the metaclass bases
    module.__init__() takes at most 2 arguments (3 given)

Original exception was:
Traceback (most recent call last):
  File "/home/scmmanager/.scm/lib/python/hgweb.py", line 42, in <module>
    wsgicgi.launch(application)
  File "/usr/lib/python2.7/dist-packages/mercurial/hgweb/wsgicgi.py", line 76, in launch
    content = application(environ, start_response)
  File "/usr/lib/python2.7/dist-packages/mercurial/hgweb/hgweb_mod.py", line 91, in __call__
    return self.run_wsgi(req)
  File "/usr/lib/python2.7/dist-packages/mercurial/hgweb/hgweb_mod.py", line 127, in run_wsgi
    return protocol.call(self.repo, req, cmd)
  File "/usr/lib/python2.7/dist-packages/mercurial/hgweb/protocol.py", line 76, in call
    rsp = wireproto.dispatch(repo, p, cmd)
  File "/usr/lib/python2.7/dist-packages/mercurial/wireproto.py", line 344, in dispatch
    return func(repo, proto, *args)
  File "/usr/lib/python2.7/dist-packages/mercurial/wireproto.py", line 578, in unbundle
    lock=lock)
  File "/usr/lib/python2.7/dist-packages/mercurial/localrepo.py", line 1944, in addchangegroup
    url=url, pending=p)
  File "/usr/lib/python2.7/dist-packages/mercurial/localrepo.py", line 239, in hook
    return hook.hook(self.ui, self, name, throw, **args)
  File "/usr/lib/python2.7/dist-packages/mercurial/hook.py", line 165, in hook
    r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
  File "/usr/lib/python2.7/dist-packages/mercurial/hook.py", line 75, in _pythonhook
    r = obj(ui=ui, repo=repo, hooktype=name, **args)
  File "/home/scmmanager/.scm/lib/python/scmhooks.py", line 67, in callback
    abort = callHookUrl(ui, repo, hooktype, node)
  File "/home/scmmanager/.scm/lib/python/scmhooks.py", line 51, in callHookUrl
    conn = urllib2.urlopen(url, data);
  File "/usr/lib/python2.7/urllib2.py", line 126, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 400, in open
    response = self._open(req, data)
  File "/usr/lib/python2.7/urllib2.py", line 418, in _open
    '_open', req)
  File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 1215, in https_open
    return self.do_open(httplib.HTTPSConnection, req)
  File "/usr/lib/python2.7/urllib2.py", line 1177, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error [Errno 6] _ssl.c:504: TLS/SSL connection has been closed>

the SSL configuration is pretty simple as just described in the wiki and looks like:

  <Call name="addConnector">
    <Arg>
      <New class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector">
        <Set name="Port">8181</Set>
        <Set name="maxIdleTime">30000</Set>
        <Set name="requestHeaderSize">16384</Set>
        <Set name="keystore"><SystemProperty name="basedir" default="." />/conf/keystore.jks</Set>
        <Set name="password">mypwd</Set>
        <Set name="keyPassword">mypwd</Set>
        <Set name="truststore"><SystemProperty name="basedir" default="." />/conf/keystore.jks</Set>
        <Set name="trustPassword">mypwd</Set>
      </New>
    </Arg>
  </Call>

Other than this, there are no changes on the configuration.

Could you please help?

Comments (26)

  1. Sebastian Sdorra repo owner

    It looks like your python installation is not able to create a request to ssl port of SCM-Manager. Could you try to stop scm-manager, access a mercurial repository over http and after that try to push over https?

    Because SCM-Manager tries to figure out the mercurial hook callback url in the following order:

    • first accessed servername and scheme
    • local url and accessed scheme
    • configured base url

    Have a look at https://bitbucket.org/sdorra/scm-manager/src/765afae0af7c/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgHookManager.java?at=default#cl-176

  2. Matthias Lang reporter

    not sure if I completely understand what you mean. I have done:

    • stopped scm manger
    • run hg serve
    • accessed a repository over http
    • stopped hg serve
    • retried push via https

    but I get the same error as before...

  3. Matthias Lang reporter

    the result is:

    CONNECTED(00000003)
    140224482604704:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:177:
    ---
    no peer certificate available
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 7 bytes and written 0 bytes
    ---
    New, (NONE), Cipher is (NONE)
    Secure Renegotiation IS NOT supported
    Compression: NONE
    Expansion: NONE
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : 0000
        Session-ID: 
        Session-ID-ctx: 
        Master-Key: 
        Key-Arg   : None
        PSK identity: None
        PSK identity hint: None
        SRP username: None
        Start Time: 1350153054
        Timeout   : 300 (sec)
        Verify return code: 0 (ok)
    ---
    
  4. Matthias Lang reporter

    Hi, I have tried so, but it gives me the error:

      Traceback (most recent call last):
      File "test.py", line 2, in <module>
        conn = urllib.urlopen("https://192.168.220.208:8181/scm");
      File "/usr/lib/python2.7/urllib.py", line 86, in urlopen
        return opener.open(url)
      File "/usr/lib/python2.7/urllib.py", line 207, in open
        return getattr(self, name)(url)
      File "/usr/lib/python2.7/urllib.py", line 436, in open_https
        h.endheaders(data)
      File "/usr/lib/python2.7/httplib.py", line 954, in endheaders
        self._send_output(message_body)
      File "/usr/lib/python2.7/httplib.py", line 814, in _send_output
        self.send(msg)
      File "/usr/lib/python2.7/httplib.py", line 776, in send
        self.connect()
      File "/usr/lib/python2.7/httplib.py", line 1161, in connect
        self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
      File "/usr/lib/python2.7/ssl.py", line 381, in wrap_socket
        ciphers=ciphers)
      File "/usr/lib/python2.7/ssl.py", line 143, in __init__
        self.do_handshake()
      File "/usr/lib/python2.7/ssl.py", line 305, in do_handshake
        self._sslobj.do_handshake()
    IOError: [Errno socket error] [Errno 6] _ssl.c:504: TLS/SSL connection has been closed
    
  5. Sebastian Sdorra repo owner

    You have to use ssl always with the servername from the cn. Could you test the python script with the servername?

    import urllib
    conn = urllib.urlopen("https://solaris:8181/scm")
    print conn.code
    
  6. Matthias Lang reporter

    Hi, I have tried it, but the python command returns the same error:

    Traceback (most recent call last):
      File "test.py", line 2, in <module>
        conn = urllib.urlopen("https://solaris:8181/scm");
      File "/usr/lib/python2.7/urllib.py", line 86, in urlopen
        return opener.open(url)
      File "/usr/lib/python2.7/urllib.py", line 207, in open
        return getattr(self, name)(url)
      File "/usr/lib/python2.7/urllib.py", line 436, in open_https
        h.endheaders(data)
      File "/usr/lib/python2.7/httplib.py", line 954, in endheaders
        self._send_output(message_body)
      File "/usr/lib/python2.7/httplib.py", line 814, in _send_output
        self.send(msg)
      File "/usr/lib/python2.7/httplib.py", line 776, in send
        self.connect()
      File "/usr/lib/python2.7/httplib.py", line 1161, in connect
        self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
      File "/usr/lib/python2.7/ssl.py", line 381, in wrap_socket
        ciphers=ciphers)
      File "/usr/lib/python2.7/ssl.py", line 143, in __init__
        self.do_handshake()
      File "/usr/lib/python2.7/ssl.py", line 305, in do_handshake
        self._sslobj.do_handshake()
    IOError: [Errno socket error] [Errno 6] _ssl.c:504: TLS/SSL connection has been closed
    

    I have also tried just to check another ssl side (https://bitbucket.org), and this works, so the issue is not with any python stuff. I have also just created a new ssl certificate and retried all the configuration steps but the result is just again the same as before... obviously there seems to be something wrong with the certificate or the way it gets used by jetty?! but using the application in a web browser works fine...

  7. Sebastian Sdorra repo owner

    I'm sure the bug is in the self-signed certificate handling of python. If the bug lays at jetty, you had problem with the browser or with the scm-manager callbacks. Could you try to install your certificate to the certificate store of solaris?

  8. Matthias Lang reporter

    sorry, but I am not very experienced with ssl on linux. Where should I store the certificate in the server? As far as I know there is no central place for such in linux?!

  9. Sebastian Sdorra repo owner

    Which linux you are running? I thought you are using solaris as os. Could you try to generate the certificate with openssl? Here is a example:

     $ openssl genrsa -des3 -out server.key 1024
     Generating RSA private key, 1024 bit long modulus
     ......++++++
     .........................................++++++
     e is 65537 (0x10001)
     Enter pass phrase for server.key:
     Verifying - Enter pass phrase for server.key:
     $ openssl req -new -x509 -nodes -sha256 -days 3650 -key server.key -out server.crt
     Enter pass phrase for server.key:
     You are about to be asked to enter information that will be incorporated
     into your certificate request.
     What you are about to enter is what is called a Distinguished Name or a DN.
     There are quite a few fields but you can leave some blank
     For some fields there will be a default value,
     If you enter '.', the field will be left blank.
     -----
     Country Name (2 letter code) [AU]:
     State or Province Name (full name) [Some-State]:
     Locality Name (eg, city) []:
     Organization Name (eg, company) [Internet Widgits Pty Ltd]:
     Organizational Unit Name (eg, section) []:
     Common Name (eg, YOUR name) []:yoursername
     Email Address []:
     $ cp server.key server.key.orig
     $ openssl rsa -in server.key.orig -out server.key
     Enter pass phrase for server.key.orig:
     writing RSA key
     $ openssl pkcs12 -export -in server.crt -inkey server.key -name server.crt -out server.p12
     Enter Export Password:
     Verifying - Enter Export Password:
     $ keytool -importkeystore -srcstoretype PKCS12 -srckeystore server.p12 -destkeystore keystore.jks
     Enter destination keystore password:  
     Re-enter new password: 
     Enter source keystore password:  
     Entry for alias server.crt successfully imported.
     Import command completed:  1 entries successfully imported, 0 entries failed or cancelled
    

    Note: Use for always the same password and enter full qualified servername at the "Common Name" question. The password you entered must be same for the server-config.xml fields in sslconnector section.

  10. Matthias Lang reporter

    Ok, I have now tested it with a certificate created by openssl, but I still get the same errors. There is no difference when using this new certificate....

  11. Matthias Lang reporter

    I have now tried it with a Oracle JDK and indeed! this seems to solve the problem. Pushing does now work! I think we can therefore close this issue. Many thanks for supporting me with this problem.

  12. Log in to comment