aa60fb
From ca08d7d3a7562588b09b78b7079b2c15e572a484 Mon Sep 17 00:00:00 2001
aa60fb
From: Fraser Tweedale <ftweedal@redhat.com>
aa60fb
Date: Wed, 6 Jan 2016 14:50:42 +1100
aa60fb
Subject: [PATCH] Do not decode HTTP reason phrase from Dogtag
aa60fb
aa60fb
The HTTP reason phrase sent by Dogtag is assumed to be encoded in
aa60fb
UTF-8, but the encoding used by Tomcat is dependent on system
aa60fb
locale, causing decode errors in some locales.
aa60fb
aa60fb
The reason phrase is optional and will not be sent in a future
aa60fb
version of Tomcat[1], so do not bother decoding and returning it.
aa60fb
aa60fb
[1] https://github.com/apache/tomcat/commit/707ab1c77f3bc189e1c3f29b641506db4c8bce37
aa60fb
aa60fb
Fixes: https://fedorahosted.org/freeipa/ticket/5578
aa60fb
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
aa60fb
---
aa60fb
 ipapython/dogtag.py         | 23 +++++++++++------------
aa60fb
 ipaserver/install/certs.py  |  7 +++----
aa60fb
 ipaserver/plugins/dogtag.py | 44 ++++++++++++++++++++++----------------------
aa60fb
 3 files changed, 36 insertions(+), 38 deletions(-)
aa60fb
aa60fb
diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py
aa60fb
index 8996902ba92f0fdd6106e2650c2decde375c593b..652bc3d13f2b47b35f6da30579f2df5f083dbff2 100644
aa60fb
--- a/ipapython/dogtag.py
aa60fb
+++ b/ipapython/dogtag.py
aa60fb
@@ -230,14 +230,14 @@ def ca_status(ca_host=None, use_proxy=True):
aa60fb
         ca_port = 443
aa60fb
     else:
aa60fb
         ca_port = 8443
aa60fb
-    status, reason, headers, body = unauthenticated_https_request(
aa60fb
+    status, headers, body = unauthenticated_https_request(
aa60fb
         ca_host, ca_port, '/ca/admin/ca/getStatus')
aa60fb
     if status == 503:
aa60fb
         # Service temporarily unavailable
aa60fb
-        return reason
aa60fb
+        return status
aa60fb
     elif status != 200:
aa60fb
         raise errors.RemoteRetrieveError(
aa60fb
-            reason=_("Retrieving CA status failed: %s") % reason)
aa60fb
+            reason=_("Retrieving CA status failed with status %d") % status)
aa60fb
     return _parse_ca_status(body)
aa60fb
 
aa60fb
 
aa60fb
@@ -248,8 +248,8 @@ def https_request(host, port, url, secdir, password, nickname,
aa60fb
     :param url: The path (not complete URL!) to post to.
aa60fb
     :param body: The request body (encodes kw if None)
aa60fb
     :param kw:  Keyword arguments to encode into POST body.
aa60fb
-    :return:   (http_status, http_reason_phrase, http_headers, http_body)
aa60fb
-               as (integer, unicode, dict, str)
aa60fb
+    :return:   (http_status, http_headers, http_body)
aa60fb
+               as (integer, dict, str)
aa60fb
 
aa60fb
     Perform a client authenticated HTTPS request
aa60fb
     """
aa60fb
@@ -277,8 +277,8 @@ def http_request(host, port, url, **kw):
aa60fb
     """
aa60fb
     :param url: The path (not complete URL!) to post to.
aa60fb
     :param kw: Keyword arguments to encode into POST body.
aa60fb
-    :return:   (http_status, http_reason_phrase, http_headers, http_body)
aa60fb
-                as (integer, unicode, dict, str)
aa60fb
+    :return:   (http_status, http_headers, http_body)
aa60fb
+                as (integer, dict, str)
aa60fb
 
aa60fb
     Perform an HTTP request.
aa60fb
     """
aa60fb
@@ -291,8 +291,8 @@ def unauthenticated_https_request(host, port, url, **kw):
aa60fb
     """
aa60fb
     :param url: The path (not complete URL!) to post to.
aa60fb
     :param kw: Keyword arguments to encode into POST body.
aa60fb
-    :return:   (http_status, http_reason_phrase, http_headers, http_body)
aa60fb
-                as (integer, unicode, dict, str)
aa60fb
+    :return:   (http_status, http_headers, http_body)
aa60fb
+                as (integer, dict, str)
aa60fb
 
aa60fb
     Perform an unauthenticated HTTPS request.
aa60fb
     """
aa60fb
@@ -331,15 +331,14 @@ def _httplib_request(
aa60fb
         res = conn.getresponse()
aa60fb
 
aa60fb
         http_status = res.status
aa60fb
-        http_reason_phrase = unicode(res.reason, 'utf-8')
aa60fb
         http_headers = res.msg.dict
aa60fb
         http_body = res.read()
aa60fb
         conn.close()
aa60fb
     except Exception, e:
aa60fb
         raise NetworkError(uri=uri, error=str(e))
aa60fb
 
aa60fb
-    root_logger.debug('response status %d %s', http_status, http_reason_phrase)
aa60fb
+    root_logger.debug('response status %d',    http_status)
aa60fb
     root_logger.debug('response headers %s',   http_headers)
aa60fb
     root_logger.debug('response body %r',      http_body)
aa60fb
 
aa60fb
-    return http_status, http_reason_phrase, http_headers, http_body
aa60fb
+    return http_status, http_headers, http_body
aa60fb
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
aa60fb
index 564332e6fde0698a23884922c5018fab59da7e4d..f8a9c9ecfd2fa1accb792c4748bc69f30701af6a 100644
aa60fb
--- a/ipaserver/install/certs.py
aa60fb
+++ b/ipaserver/install/certs.py
aa60fb
@@ -402,12 +402,11 @@ class CertDB(object):
aa60fb
                 dogtag.configured_constants().EE_SECURE_PORT,
aa60fb
             "/ca/ee/ca/profileSubmitSSLClient",
aa60fb
             self.secdir, password, "ipaCert", **params)
aa60fb
-        http_status, http_reason_phrase, http_headers, http_body = result
aa60fb
+        http_status, http_headers, http_body = result
aa60fb
 
aa60fb
         if http_status != 200:
aa60fb
             raise CertificateOperationError(
aa60fb
-                error=_('Unable to communicate with CMS (%s)') %
aa60fb
-                    http_reason_phrase)
aa60fb
+                error=_('Unable to communicate with CMS (status %d)') % http_status)
aa60fb
 
aa60fb
         # The result is an XML blob. Pull the certificate out of that
aa60fb
         doc = xml.dom.minidom.parseString(http_body)
aa60fb
@@ -459,7 +458,7 @@ class CertDB(object):
aa60fb
                 dogtag.configured_constants().EE_SECURE_PORT,
aa60fb
             "/ca/ee/ca/profileSubmitSSLClient",
aa60fb
             self.secdir, password, "ipaCert", **params)
aa60fb
-        http_status, http_reason_phrase, http_headers, http_body = result
aa60fb
+        http_status, http_headers, http_body = result
aa60fb
         if http_status != 200:
aa60fb
             raise RuntimeError("Unable to submit cert request")
aa60fb
 
aa60fb
diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
aa60fb
index f5f8eb67067c87f07c06e556fb9fc73792fbbc64..3029a9144d80a9b081853b95259fcd37e35d8c2b 100644
aa60fb
--- a/ipaserver/plugins/dogtag.py
aa60fb
+++ b/ipaserver/plugins/dogtag.py
aa60fb
@@ -1350,8 +1350,8 @@ class ra(rabase.rabase):
aa60fb
         """
aa60fb
         :param url: The URL to post to.
aa60fb
         :param kw: Keyword arguments to encode into POST body.
aa60fb
-        :return:   (http_status, http_reason_phrase, http_headers, http_body)
aa60fb
-                   as (integer, unicode, dict, str)
aa60fb
+        :return:   (http_status, http_headers, http_body)
aa60fb
+                   as (integer, dict, str)
aa60fb
 
aa60fb
         Perform an HTTP request.
aa60fb
         """
aa60fb
@@ -1361,8 +1361,8 @@ class ra(rabase.rabase):
aa60fb
         """
aa60fb
         :param url: The URL to post to.
aa60fb
         :param kw:  Keyword arguments to encode into POST body.
aa60fb
-        :return:   (http_status, http_reason_phrase, http_headers, http_body)
aa60fb
-                   as (integer, unicode, dict, str)
aa60fb
+        :return:   (http_status, http_headers, http_body)
aa60fb
+                   as (integer, dict, str)
aa60fb
 
aa60fb
         Perform an HTTPS request
aa60fb
         """
aa60fb
@@ -1422,7 +1422,7 @@ class ra(rabase.rabase):
aa60fb
         self.debug('%s.check_request_status()', self.fullname)
aa60fb
 
aa60fb
         # Call CMS
aa60fb
-        http_status, http_reason_phrase, http_headers, http_body = \
aa60fb
+        http_status, http_headers, http_body = \
aa60fb
             self._request('/ca/ee/ca/checkRequest',
aa60fb
                           self.env.ca_port,
aa60fb
                           requestId=request_id,
aa60fb
@@ -1431,7 +1431,7 @@ class ra(rabase.rabase):
aa60fb
         # Parse and handle errors
aa60fb
         if http_status != 200:
aa60fb
             self.raise_certificate_operation_error('check_request_status',
aa60fb
-                                                   detail=http_reason_phrase)
aa60fb
+                                                   detail=http_status)
aa60fb
 
aa60fb
         parse_result = self.get_parse_result_xml(http_body, parse_check_request_result_xml)
aa60fb
         request_status = parse_result['request_status']
aa60fb
@@ -1507,7 +1507,7 @@ class ra(rabase.rabase):
aa60fb
         serial_number = int(serial_number, 0)
aa60fb
 
aa60fb
         # Call CMS
aa60fb
-        http_status, http_reason_phrase, http_headers, http_body = \
aa60fb
+        http_status, http_headers, http_body = \
aa60fb
             self._sslget('/ca/agent/ca/displayBySerial',
aa60fb
                          self.env.ca_agent_port,
aa60fb
                          serialNumber=str(serial_number),
aa60fb
@@ -1517,7 +1517,7 @@ class ra(rabase.rabase):
aa60fb
         # Parse and handle errors
aa60fb
         if http_status != 200:
aa60fb
             self.raise_certificate_operation_error('get_certificate',
aa60fb
-                                                   detail=http_reason_phrase)
aa60fb
+                                                   detail=http_status)
aa60fb
 
aa60fb
         parse_result = self.get_parse_result_xml(http_body, parse_display_cert_xml)
aa60fb
         request_status = parse_result['request_status']
aa60fb
@@ -1575,7 +1575,7 @@ class ra(rabase.rabase):
aa60fb
         self.debug('%s.request_certificate()', self.fullname)
aa60fb
 
aa60fb
         # Call CMS
aa60fb
-        http_status, http_reason_phrase, http_headers, http_body = \
aa60fb
+        http_status, http_headers, http_body = \
aa60fb
             self._sslget('/ca/eeca/ca/profileSubmitSSLClient',
aa60fb
                          self.env.ca_ee_port,
aa60fb
                          profileId=profile_id,
aa60fb
@@ -1585,7 +1585,7 @@ class ra(rabase.rabase):
aa60fb
         # Parse and handle errors
aa60fb
         if http_status != 200:
aa60fb
             self.raise_certificate_operation_error('request_certificate',
aa60fb
-                                                   detail=http_reason_phrase)
aa60fb
+                                                   detail=http_status)
aa60fb
 
aa60fb
         parse_result = self.get_parse_result_xml(http_body, parse_profile_submit_result_xml)
aa60fb
         # Note different status return, it's not request_status, it's error_code
aa60fb
@@ -1654,7 +1654,7 @@ class ra(rabase.rabase):
aa60fb
         serial_number = int(serial_number, 0)
aa60fb
 
aa60fb
         # Call CMS
aa60fb
-        http_status, http_reason_phrase, http_headers, http_body = \
aa60fb
+        http_status, http_headers, http_body = \
aa60fb
             self._sslget('/ca/agent/ca/doRevoke',
aa60fb
                          self.env.ca_agent_port,
aa60fb
                          op='revoke',
aa60fb
@@ -1666,7 +1666,7 @@ class ra(rabase.rabase):
aa60fb
         # Parse and handle errors
aa60fb
         if http_status != 200:
aa60fb
             self.raise_certificate_operation_error('revoke_certificate',
aa60fb
-                                                   detail=http_reason_phrase)
aa60fb
+                                                   detail=http_status)
aa60fb
 
aa60fb
         parse_result = self.get_parse_result_xml(http_body, parse_revoke_cert_xml)
aa60fb
         request_status = parse_result['request_status']
aa60fb
@@ -1717,7 +1717,7 @@ class ra(rabase.rabase):
aa60fb
         serial_number = int(serial_number, 0)
aa60fb
 
aa60fb
         # Call CMS
aa60fb
-        http_status, http_reason_phrase, http_headers, http_body = \
aa60fb
+        http_status, http_headers, http_body = \
aa60fb
             self._sslget('/ca/agent/ca/doUnrevoke',
aa60fb
                          self.env.ca_agent_port,
aa60fb
                          serialNumber=str(serial_number),
aa60fb
@@ -1726,7 +1726,7 @@ class ra(rabase.rabase):
aa60fb
         # Parse and handle errors
aa60fb
         if http_status != 200:
aa60fb
             self.raise_certificate_operation_error('take_certificate_off_hold',
aa60fb
-                                                   detail=http_reason_phrase)
aa60fb
+                                                   detail=http_status)
aa60fb
 
aa60fb
 
aa60fb
         parse_result = self.get_parse_result_xml(http_body, parse_unrevoke_cert_xml)
aa60fb
@@ -2027,7 +2027,7 @@ class RestClient(Backend):
aa60fb
         """Log into the REST API"""
aa60fb
         if self.cookie is not None:
aa60fb
             return
aa60fb
-        status, status_text, resp_headers, resp_body = dogtag.https_request(
aa60fb
+        status, resp_headers, resp_body = dogtag.https_request(
aa60fb
             self.ca_host, self.override_port or self.env.ca_agent_port,
aa60fb
             '/ca/rest/account/login',
aa60fb
             self.sec_dir, self.password, self.ipa_certificate_nickname,
aa60fb
@@ -2053,8 +2053,8 @@ class RestClient(Backend):
aa60fb
         """
aa60fb
         :param url: The URL to post to.
aa60fb
         :param kw:  Keyword arguments to encode into POST body.
aa60fb
-        :return:   (http_status, http_reason_phrase, http_headers, http_body)
aa60fb
-                   as (integer, unicode, dict, str)
aa60fb
+        :return:   (http_status, http_headers, http_body)
aa60fb
+                   as (integer, dict, str)
aa60fb
 
aa60fb
         Perform an HTTPS request
aa60fb
         """
aa60fb
@@ -2068,7 +2068,7 @@ class RestClient(Backend):
aa60fb
         resource = os.path.join('/ca/rest', self.path, path)
aa60fb
 
aa60fb
         # perform main request
aa60fb
-        status, status_text, resp_headers, resp_body = dogtag.https_request(
aa60fb
+        status, resp_headers, resp_body = dogtag.https_request(
aa60fb
             self.ca_host, self.override_port or self.env.ca_agent_port,
aa60fb
             resource,
aa60fb
             self.sec_dir, self.password, self.ipa_certificate_nickname,
aa60fb
@@ -2077,10 +2077,10 @@ class RestClient(Backend):
aa60fb
         if status < 200 or status >= 300:
aa60fb
             explanation = self._parse_dogtag_error(resp_body) or ''
aa60fb
             raise errors.RemoteRetrieveError(
aa60fb
-                reason=_('Non-2xx response from CA REST API: %(status)d %(status_text)s. %(explanation)s')
aa60fb
-                % {'status': status, 'status_text': status_text, 'explanation': explanation}
aa60fb
+                reason=_('Non-2xx response from CA REST API: %(status)d. %(explanation)s')
aa60fb
+                % {'status': status, 'explanation': explanation}
aa60fb
             )
aa60fb
-        return (status, status_text, resp_headers, resp_body)
aa60fb
+        return (status, resp_headers, resp_body)
aa60fb
 
aa60fb
 
aa60fb
 class ra_certprofile(RestClient):
aa60fb
@@ -2105,7 +2105,7 @@ class ra_certprofile(RestClient):
aa60fb
         """
aa60fb
         Read the profile configuration from Dogtag
aa60fb
         """
aa60fb
-        status, status_text, resp_headers, resp_body = self._ssldo(
aa60fb
+        status, resp_headers, resp_body = self._ssldo(
aa60fb
             'GET', profile_id + '/raw')
aa60fb
         return resp_body
aa60fb
 
aa60fb
-- 
aa60fb
2.5.0
aa60fb