Bug 848475 - setup with multiple tiered proxy doesn't work - authentication tokens aren't regenerated
Summary: setup with multiple tiered proxy doesn't work - authentication tokens aren't ...
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: Spacewalk
Classification: Community
Component: Server
Version: 1.8
Hardware: All
OS: Linux
high
high
Target Milestone: ---
Assignee: Stephen Herr
QA Contact: Red Hat Satellite QA List
URL:
Whiteboard:
Depends On: 769908 848802
Blocks: space18
TreeView+ depends on / blocked
 
Reported: 2012-08-15 17:20 UTC by Stephen Herr
Modified: 2018-12-09 16:50 UTC (History)
7 users (show)

Fixed In Version: spacewalk-backend-1.8.62-1 spacewalk-proxy-1.8.11-1
Doc Type: Bug Fix
Doc Text:
Clone Of: 769908
Environment:
Last Closed: 2012-11-01 16:21:31 UTC
Embargoed:


Attachments (Terms of Use)

Description Stephen Herr 2012-08-15 17:20:04 UTC
+++ This bug was initially created as a clone of Bug #769908 +++

Description of problem:

the following scenario doesn't work:

http://docs.redhat.com/docs/en-US/Red_Hat_Network_Satellite/5.4/html-single/Proxy_Installation_Guide/index.html#sect-Proxy_Installation_Guide-Example_Topologies-Multiple_Proxy_Vertically_Tiered_Topology


Version-Release number of selected component (if applicable):

spacewalk-proxy-redirect-1.2.2-12.el6sat.noarch
spacewalk-proxy-broker-1.2.2-12.el6sat.noarch


How reproducible:

Always


Steps to Reproduce:

1. Setup a scenario with at least one tiered proxy (if a client is connected only trough one proxy to xmlrpc.rhn.redhat.com everthing works correctly):

RHEL5 client <-> Proxy num. 2 <-> Proxy num. 1 <-> xmlrpc.rhn.redhat.com

2. Do yum clean all and makecache (to let auth token create if it doesn't exist already) and wait 6 hours (default timeout) for token to expire or change the code to create tokens with lower offset

3. Run again yum clan all and makecache and you will see the 'Actual results'.

  
Actual results:

client# yum clean all
client# yum makecache
Loaded plugins: product-id, rhnplugin, security, subscription-manager
Updating Red Hat repositories.
Error: Cannot retrieve repository metadata (repomd.xml) for repository: redhat-rhn-proxy-5.4-server-x86_64-5. Please verify its path and try again
client#


Expected results:

the metadata should be created without the error

client# yum clean all
client# yum makecache
Loaded plugins: product-id, rhnplugin, security, subscription-manager
Updating Red Hat repositories.
redhat-rhn-proxy-5.4-server-x86_64-5                                                                                                                                                    | 1.3 kB     00:00     
redhat-rhn-proxy-5.4-server-x86_64-5/filelists                                                                                                                                          |  27 kB     00:00     
redhat-rhn-proxy-5.4-server-x86_64-5/updateinfo                                                                                                                                         |  10 kB     00:00     
redhat-rhn-proxy-5.4-server-x86_64-5/other                                                                                                                                              | 173 kB     00:00     
redhat-rhn-proxy-5.4-server-x86_64-5/primary
...


Additional info:

The code which regenerates the authentication tokens depends on 'X-RHN-Proxy-Auth-Error' header in the html reply for every method (GET, CONNECT, HEAD, PUT, POST):

spacewalk-proxy-1.2.2/broker/rhnBroker.py:
138     def handler(self):
...
215             respHeaders = self.responseContext.getHeaders()
216             if not respHeaders or \
217                not respHeaders.has_key('X-RHN-Proxy-Auth-Error'):
...
221                 break
222
223             # Expired/invalid auth token; go through the loop once again
224             error = string.split(respHeaders['X-RHN-Proxy-Auth-Error'], ':')[0]
225             if error == '1003': # invalid token
226                 msg = "RHN Proxy Session Token INVALID -- bad!"
227                 log_error(msg)
228                 log_debug(0, msg)
229             elif error == '1004':
230                 log_debug(1,
231                     "RHN Proxy Session Token expired, acquiring new one.")
232             else: # this should never happen.
233                 msg = "RHN Proxy login failed, error code is %s" % error
234                 log_error(msg)
235                 log_debug(0, msg)
236                 raise rhnFault(1000,
237                   _("RHN Proxy error (issues with proxy login). "
238                     "Please contact your system administrator."))
239 
240             # Forced refresh of the proxy token
241             rhnFlags.get('outputTransportOptions')['X-RHN-Proxy-Auth'] = self.proxyAuth.check_cached_token(1)

but it doesn't work for GET method which is the only one which gets redirected through squid to redirect component and then to xmlrpc.rhn.redhat.com, unfortunately the reply from squid/redirect component doesn't contain the original 'X-RHN-Proxy-Auth-Error' header sent by xmlrpc.rhn.redhat.com, but only squid headers so that tiered proxies don't get the error from 'X-RHN-Proxy-Auth-Error' header so they didn't regenerate the authentication token (the line #241 from above snippet doesn't get called) which leads to xmlrpc.rhn.redhat.com denying the client to proceed.

Look at reply from xmlrpc.rhn.redhat.com to proxy num. 1:

"""
GET http://xmlrpc.rhn.redhat.com/XMLRPC/GET-REQ/rhel-x86_64-server-5/repodata/repomd.xml HTTP/1.1
Host: xmlrpc.rhn.redhat.com
Accept-Encoding: identity
X-RHN-Auth-Expire-Offset: 3600.0
User-Agent: rhn.rpclib.py/$Revision: 190936 $
X-RHN-Auth-Server-Time: 1323859770.12
X-RHN-Transport-Capability: follow-redirects=3
Accept-Encoding: identity, identity, identity
X-RHN-Proxy-Version: 5.4.0
Connection: keep-alive
X-RHN-Auth: rMaSP<removed>wdK/apJA==
X-RHN-Proxy-Auth: 1021083084::1323365915.72:21600.0:Qwof8t3<removed>KNptdW4A==:<removed proxy num2hostname>,1021076977::1323859769.52:21600.0:Tmilqxu<removed>ntkqz3qWQ==:removed proxy num1hostname
Via: 1.1 <removed> (squid/3.1.10), 1.1 <removed> (squid/3.1.10)
X-RHN-Server-Id: 1021012641
Pragma: no-cache
X-Forwarded-For: <removed>,<removed>
X-RHN-Ip-Path: <removed>,<removed>
Cache-Control: max-age=31536000
X-RHN-Auth-User-Id: 

HTTP/1.1 404 Not Found
Via: 1.1 <removed>, 1.1 <removed>
Connection: Keep-Alive
Proxy-Connection: Keep-Alive
Content-Length: 1
Date: Wed, 14 Dec 2011 10:49:30 GMT
Content-Type: text/html; charset=iso-8859-1
Server: Apache
X-RHN-Fault-Code: -1004
X-RHN-Fault-String: CkVycm9yIENsYXNzIENvZGU6IDEwMDQKRXJyb3IgQ2xhc3MgSW5mbzogUkhOIFByb3h5IHNlc3Np
X-RHN-Fault-String: b24gdG9rZW4gaGFzIGV4cGlyZWQuCkV4cGxhbmF0aW9uOiAKICAgICBBbiBlcnJvciBoYXMgb2Nj
X-RHN-Fault-String: dXJyZWQgd2hpbGUgcHJvY2Vzc2luZyB5b3VyIHJlcXVlc3QuIElmIHRoaXMgcHJvYmxlbQogICAg
X-RHN-Fault-String: IHBlcnNpc3RzIHBsZWFzZSBlbnRlciBhIGJ1ZyByZXBvcnQgYXQgYnVnemlsbGEucmVkaGF0LmNv
X-RHN-Fault-String: bS4KICAgICBJZiB5b3UgY2hvb3NlIHRvIHN1Ym1pdCB0aGUgYnVnIHJlcG9ydCwgcGxlYXNlIGJl
X-RHN-Fault-String: IHN1cmUgdG8gaW5jbHVkZQogICAgIGRldGFpbHMgb2Ygd2hhdCB5b3Ugd2VyZSB0cnlpbmcgdG8g
X-RHN-Fault-String: ZG8gd2hlbiB0aGlzIGVycm9yIG9jY3VycmVkIGFuZAogICAgIGRldGFpbHMgb24gaG93IHRvIHJl
X-RHN-Fault-String: cHJvZHVjZSB0aGlzIHByb2JsZW0uCg==
X-RHN-Proxy-Version: 5.4.0
X-RHN-Proxy-Auth-Error: 1004:Expired
X-RHN-Client-Version: 0
"""

and the reply from the proxy num. 1 to proxy num. 2:

"""
GET /XMLRPC/GET-REQ/rhel-x86_64-server-5/repodata/repomd.xml HTTP/1.1
Host: <removed>
Accept-Encoding: identity
X-RHN-IP-Path: 10.219.4.18
User-Agent: rhn.rpclib.py/$Revision: 190936 $
X-RHN-Auth-Server-Time: 1323859765.48
X-RHN-Transport-Capability: follow-redirects=3
Pragma: no-cache
Accept-Encoding: identity
X-RHN-Auth-Expire-Offset: 3600.0
X-RHN-Proxy-Version: 5.4.0
X-RHN-Auth: mVky40SUhBkZtE0p14vXBQ==
X-RHN-Proxy-Auth: 1021083084::1323365915.72:21600.0:Qwof8t3<removed>KNptdW4A==:<removed proxy num2hostname>
X-RHN-Server-Id: 1021012641
X-RHN-Auth-User-Id: 
Via: 1.1 <removed> (squid/3.1.10)
X-Forwarded-For: 127.0.0.1
Cache-Control: max-age=31536000
Connection: keep-alive

HTTP/1.1 404 Not Found
Date: Wed, 14 Dec 2011 10:49:25 GMT
Server: Apache/2.2.15 (Red Hat)
Content-Length: 0
Connection: close
Content-Type: text/xml
"""

From above we can see that reply to the second proxy doesn't contain 'X-RHN-Proxy-Auth-Error'.

I added a debug statement (line #196) to proxy code to see what broker gets from redirect:

/usr/share/rhn/proxy/rhnShared.py:
177     def _serverCommo(self, data):
...
193         # Send the headers, the body and expect a response
194         try:
195             status, headers, bodyFd = self._proxy2server(data)
196             log_debug(2, "headers: %s" % headers)

and here it is:

xmlrpc.rhn.redhat.com -> redirect:

2011/12/19 13:46:59 -04:00 12608 10.34.35.100, 127.0.0.1: proxy/rhnShared._serverCommo('headers: Date: Mon, 19 Dec 2011 18:46:59 GMT\r\nServer: Apache\r\nX-RHN-Fault-Code: -1004\r\nX-RHN-Fault-String: CkVycm9yIENsYXNzIENvZGU6IDEwMDQKRXJyb3IgQ2xhc3MgSW5mbzogUkhOIFByb3h5IHNlc3Np\r\nX-RHN-Fault-String: b24gdG9rZW4gaGFzIGV4cGlyZWQuCkV4cGxhbmF0aW9uOiAKICAgICBBbiBlcnJvciBoYXMgb2Nj\r\nX-RHN-Fault-String: dXJyZWQgd2hpbGUgcHJvY2Vzc2luZyB5b3VyIHJlcXVlc3QuIElmIHRoaXMgcHJvYmxlbQogICAg\r\nX-RHN-Fault-String: IHBlcnNpc3RzIHBsZWFzZSBlbnRlciBhIGJ1ZyByZXBvcnQgYXQgYnVnemlsbGEucmVkaGF0LmNv\r\nX-RHN-Fault-String: bS4KICAgICBJZiB5b3UgY2hvb3NlIHRvIHN1Ym1pdCB0aGUgYnVnIHJlcG9ydCwgcGxlYXNlIGJl\r\nX-RHN-Fault-String: IHN1cmUgdG8gaW5jbHVkZQogICAgIGRldGFpbHMgb2Ygd2hhdCB5b3Ugd2VyZSB0cnlpbmcgdG8g\r\nX-RHN-Fault-String: ZG8gd2hlbiB0aGlzIGVycm9yIG9jY3VycmVkIGFuZAogICAgIGRldGFpbHMgb24gaG93IHRvIHJl\r\nX-RHN-Fault-String: cHJvZHVjZSB0aGlzIHByb2JsZW0uCg==\r\nX-RHN-Proxy-Version: 5.4.0\r\nX-RHN-Proxy-Auth-Error: 1004:Expired\r\nX-RHN-Client-Version: 0\r\nContent-Length: 1\r\nContent-Type: text/html; charset=iso-8859-1\r\nConnection: close\r\n',)

redirect -> broker:

2011/12/19 13:46:59 -04:00 12610 10.34.35.100: proxy/rhnShared._serverCommo('headers: Date: Mon, 19 Dec 2011 18:46:59 GMT\r\nServer: Apache/2.2.15 (Red Hat)\r\nContent-Length: 0\r\nContent-Type: text/xml\r\nX-Cache: MISS from tyan-gt24-11.rhts.eng.bos.redhat.com\r\nX-Cache-Lookup: MISS from tyan-gt24-11.rhts.eng.bos.redhat.com:8080\r\nVia: 1.0 tyan-gt24-11.rhts.eng.bos.redhat.com (squid/3.1.10)\r\nConnection: keep-alive\r\n',)

I can see that a code which gets called straight after a code which obtains a results from parent proxy that it adds the error headers, but there is no routine which would send them back to the broker even the comment mentions:

"By default, we will wrap all the headers up and send them back to the client with an error status.":

Yes, it will wrap them but won't send them:

spacewalk-proxy-1.2.2/rhnShared.py:
219     def _handleServerResponse(self, status):
220         """ This method can be overridden by subclasses who want to handle server
221             responses in their own way.  By default, we will wrap all the headers up
222             and send them back to the client with an error status.  This method
223             should return apache.OK if everything went according to plan.
224         """
225         if (status != apache.HTTP_OK) and (status != apache.HTTP_PARTIAL_CONTENT):
226             # Non 200 response; have to treat it differently
227             log_debug(2, "Forwarding status %s" % status)
228             # Copy the incoming headers to err_headers_out
229             headers = self.responseContext.getHeaders()
230             if headers is not None:
231                 for k in headers.keys():
232                     rhnLib.setHeaderValue(self.req.err_headers_out, k,
233                         self._get_header(k))

I tried to add the following, but although it works correctly for passing the headers from redirect to broker, it doesn't work correctly between two proxies in case the proxy returns correct results/HTTP_OK:

diff -up /usr/share/rhn/proxy/rhnShared.py.orig /usr/share/rhn/proxy/rhnShared.py
--- /usr/share/rhn/proxy/rhnShared.py.orig      2011-12-22 11:43:52.150335792 -0500
+++ /usr/share/rhn/proxy/rhnShared.py   2011-12-22 11:44:00.817662510 -0500
@@ -231,6 +231,8 @@ class SharedHandler:
                 for k in headers.keys():
                     rhnLib.setHeaderValue(self.req.err_headers_out, k,
                         self._get_header(k))
+                bodyFd = self.responseContext.getBodyFd()
+                self._forwardHTTPHeaders(bodyFd, self.req)
             else:
                 log_error('WARNING? - no incoming headers found!')
             # And that's that


Temporary workaround:

regularly remove contents of /var/cache/rhn/proxy-auth directory on every proxy server except the top level one. It could be achieved by adding the following line into /etc/crontab (+service crond restart):

0 */4 * * * root rm -rf /var/cache/rhn/proxy-auth/*

It will remove contents of that directory every 4 hours (the default timeout is 6 hours). If the command is called directly on the command line, it will fix his problem immediately.

--- Additional comment from mosvald on 2011-12-22 16:03:46 EST ---

the following demonstrates the problem more clearly (auth token doesn't get regenerated after 6 hours, the same auth token is cached for several days):

# grep "auth token for this machine only" rhn_proxy_broker.log:
...
2011/12/09 15:04:43 +02:00 1576 <ip>: broker/rhnBroker.handler('XXX auth token for this machine only! 1021083084::1323365915.72:21600.0:Qwof8t3yuPmLBwKNptdW4A==:proxynum2',)
...
2011/12/14 11:49:30 +02:00 12632 <ip>: broker/rhnBroker.handler('XXX auth token for this machine only! 1021083084::1323365915.72:21600.0:Qwof8t3yuPmLBwKNptdW4A==:proxynum2',)

--- Additional comment from sherr on 2012-08-14 17:14:39 EDT ---

To reproduce in a time less than 6 hours change the default timeout values for creating client auth tokens. To do so on the Satellite:
In /usr/share/rhn/config-defaults/rhn_server_iss.conf:
satellite_auth_timeout = 60.0 # one minute
In /usr/share/rhn/config-defaults/rhn_server.conf:
client_auth_timeout = 60.0 # one minute
proxy_auth_timeout = 60.0 # one minute

Note: to reproduce you must be using SSL for the proxies.

I feel confident that I will be able to finish tracking this problem back to its source tomorrow.

--- Additional comment from sherr on 2012-08-15 13:10:54 EDT ---

Okay, here is the problem written out as a conversation:

client -> proxy1 -> proxy2 -> satellite

1) client: I want this thing.
2) proxy1: I'll forward this on for you and attach my auth token.
3) proxy2: I'll forward this on for you and attach my auth tokan (in addition to the one that already is there).
4) satellite: 404, your auth token is expired.
5) proxy2: Oh thanks, I'll update my auth token.
6) proxy2: Now that that's taken care of, here's the request again. I'll add my new auth token to the one that's already there.
7) satellite: 404, Your auth token is expired.
8) proxy2: Oh thanks, I'll update my auth token.
9) proxy2: Well, I tried 2 times and got a 404 each time so it must not be an auth token problem, let's return the 404 to the user. Let's also helpfully clear out these nasty auth token error headers.
10) proxy 1: Looks like I got a 404, but it doesn't say there's anything wrong with my auth token so it must be fine. I'll return this to the user.
11) client: Oh no! 404!

This happens regardless of whether we are using SSL or not, the only difference is that when we're not using SSL the Satellite instead of sending a 404 will send the requested content because it doesn't matter that the auth token is invalid, so the client will actually get the content he requested.

What I have done is:
1) Updated the Satellite so that when it says "your auth token is expired" we include the hostname of the proxy that needs to update its auth token.
2) Updated the proxies to look at the hostname, and if the message is not meant for me pass it on up.

This problem could also exist if a Proxy's auth token is invalid (corrupted) and not just expired, which is a different error; 1003. I have fixed it there as well.

Comment 1 Stephen Herr 2012-08-15 17:25:58 UTC
Committed to Spacewalk master: 368bac09e763912a256acd9c3c1661190b7018ae

Comment 2 Stephen Herr 2012-08-16 14:16:01 UTC
And: 4f638b46e2c3fe93dfc19e3100d85c2e229c8265

Comment 3 Stephen Herr 2012-08-21 18:49:12 UTC
And: e3c1b2f082ef1e36a6e60dd9e9de22be616d05ab

Comment 4 Stephen Herr 2012-08-27 15:06:26 UTC
Also detect ipv6 addresses (case never observed in the wild, but it might happen:
4b4c1147351dd2c210d1d907ec53f47cd71e9914

Comment 5 Jan Pazdziora 2012-10-30 19:25:40 UTC
Moving ON_QA. Packages that address this bugzilla should now be available in yum repos at http://yum.spacewalkproject.org/nightly/

Comment 6 Jan Pazdziora 2012-11-01 16:21:31 UTC
Spacewalk 1.8 has been released: https://fedorahosted.org/spacewalk/wiki/ReleaseNotes18


Note You need to log in before you can comment on or make changes to this bug.