Package backend :: Package server :: Module apacheAuth
[hide private]
[frames] | no frames]

Source Code for Module backend.server.apacheAuth

  1  # 
  2  # Copyright (c) 2008--2016 Red Hat, Inc. 
  3  # 
  4  # This software is licensed to you under the GNU General Public License, 
  5  # version 2 (GPLv2). There is NO WARRANTY for this software, express or 
  6  # implied, including the implied warranties of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 
  8  # along with this software; if not, see 
  9  # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 
 10  # 
 11  # Red Hat trademarks are not licensed under GPLv2. No permission is 
 12  # granted to use or replicate Red Hat trademarks that are incorporated 
 13  # in this software or its documentation. 
 14  # 
 15  # 
 16   
 17  import time 
 18  import string 
 19  import re 
 20   
 21  from spacewalk.common import rhnFlags 
 22  from spacewalk.common.rhnLog import log_debug, log_error 
 23  from spacewalk.common.rhnConfig import CFG 
 24  from spacewalk.common.rhnException import rhnFault 
 25  from spacewalk.common.rhnTranslate import _ 
 26   
 27  from rhnLib import computeSignature 
 28   
 29   
30 -def splitProxyAuthToken(token):
31 """ given a token:hostname, split it into a token-list, hostname """ 32 33 token = string.split(token, ':') 34 hostname = '' 35 if len(token) > 5: 36 hostname = token[-1] 37 token = token[:-1] 38 else: 39 # Spacewalk Proxy v1.1 (route tracking unsupported) 40 hostname = None 41 return token, hostname
42 43
44 -def _verifyProxyAuthToken(auth_token):
45 """ verifies the validity of a proxy auth token 46 47 NOTE: X-RHN-Proxy-Auth described in proxy/broker/rhnProxyAuth.py 48 """ 49 50 log_debug(4, auth_token) 51 token, hostname = splitProxyAuthToken(auth_token) 52 hostname = hostname.strip() 53 ipv4_regex = '^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$' 54 # This ipv6 regex was develeoped by Stephen Ryan at Dataware. 55 # (http://forums.intermapper.com/viewtopic.php?t=452) It is licenced 56 # under a Creative Commons Attribution-ShareAlike 3.0 Unported 57 # License, so we are free to use it as long as we attribute it to him. 58 ipv6_regex = '^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?$' 59 hostname_is_ip_address = re.match(ipv4_regex, hostname) or re.match(ipv6_regex, hostname) 60 61 headers = rhnFlags.get('outputTransportOptions') 62 if len(token) < 5: 63 # Bad auth information; decline any action 64 log_debug(4, "incomplete proxy authentication token: %s" 65 % auth_token) 66 headers['X-RHN-Proxy-Auth-Error'] = '%s:%s' % ( 67 1003, _("incomplete proxy authentication token: %s") % auth_token) 68 if not hostname_is_ip_address: 69 headers['X-RHN-Proxy-Auth-Origin'] = hostname 70 raise rhnFault(1003) # Invalid session key 71 72 log_debug(5, "proxy auth token: %s, hostname: %s" 73 % (repr(token), hostname or 'n/a')) 74 75 proxyId, proxyUser, rhnServerTime, expireOffset, signature = token[:5] 76 computed = computeSignature(CFG.SECRET_KEY, proxyId, proxyUser, 77 rhnServerTime, expireOffset) 78 79 if computed != signature: 80 log_error("Proxy signature failed: proxy id='%s', proxy user='%s'" % 81 (proxyId, proxyUser)) 82 log_debug(4, "Sent proxy signature %s does not match ours %s." % ( 83 signature, computed)) 84 headers['X-RHN-Proxy-Auth-Error'] = '%s:%s' % ( 85 1003, _("Sent proxy signature %s does not match ours %s.") % ( 86 signature, computed)) 87 if not hostname_is_ip_address: 88 headers['X-RHN-Proxy-Auth-Origin'] = hostname 89 raise rhnFault(1003) # Invalid session key 90 91 # Convert the expiration/time to floats: 92 rhnServerTime = float(rhnServerTime) 93 expireOffset = float(expireOffset) 94 95 if rhnServerTime + expireOffset < time.time(): 96 log_debug(4, "Expired proxy authentication token") 97 headers['X-RHN-Proxy-Auth-Error'] = '%s:%s' % (1004, "Expired") 98 if not hostname_is_ip_address: 99 headers['X-RHN-Proxy-Auth-Origin'] = hostname 100 raise rhnFault(1004) # Expired client authentication token 101 102 log_debug(4, "Proxy auth OK: sigs match; not an expired token") 103 return 1
104 105
106 -def auth_proxy():
107 """ Authenticates a proxy carrying a clients request. For a valid or 108 unsigned request, this function returns 1 (OK), otherwise it raises 109 rhnFault 110 111 NOTE: X-RHN-Proxy-Auth described in proxy/broker/rhnProxyAuth.py 112 """ 113 114 log_debug(3) 115 headers = rhnFlags.get('outputTransportOptions') 116 if not rhnFlags.test('X-RHN-Proxy-Auth'): 117 # No auth information; decline any action 118 log_debug(4, "declined proxy authentication") 119 headers['X-RHN-Proxy-Auth-Error'] = '%s:%s' % ( 120 1003, _("declined proxy authentication")) 121 raise rhnFault(1003) # Invalid session key 122 123 # NOTE: 124 # - < v3.1 RHN proxies send only 1 token in this header 125 # - > v3.1: we send the route of the requests via multiple tokens 126 # "token1:hostname1,token2:hostname2" the first tuple is the first 127 # proxy hit. 128 129 tokens = string.split(rhnFlags.get('X-RHN-Proxy-Auth'), ',') 130 tokens = [token for token in tokens if token] 131 132 for auth_token in tokens: 133 _verifyProxyAuthToken(auth_token) 134 135 # if no rhnFault was raised then the tokens all passed 136 return 1
137 138
139 -def auth_client():
140 """ Authenticates a request from a client 141 For an unsigned request, this function returns 0 (request should be 142 coming from a client). 143 """ 144 145 log_debug(3) 146 if not rhnFlags.test("AUTH_SESSION_TOKEN"): 147 # No auth information; decline any GET action (XMLRPC requests 148 # ignore this error). 149 log_debug(4, "declined client authentication for GET requests") 150 return 0 151 152 token = dict((k.lower(),v) for k,v in rhnFlags.get("AUTH_SESSION_TOKEN").items()) 153 # Check to see if everything we need to compute the signature is there 154 for k in ('x-rhn-server-id', 155 'x-rhn-auth-user-id', 156 'x-rhn-auth', 157 'x-rhn-auth-server-time', 158 'x-rhn-auth-expire-offset'): 159 if k not in token: 160 # No auth information; decline any action 161 log_debug(4, "Declined auth of client for GET requests; " 162 "incomplete header info.") 163 return 0 164 165 clientId = token['x-rhn-server-id'] 166 username = token['x-rhn-auth-user-id'] 167 signature = token['x-rhn-auth'] 168 rhnServerTime = token['x-rhn-auth-server-time'] 169 expireOffset = token['x-rhn-auth-expire-offset'] 170 171 172 computed = computeSignature(CFG.SECRET_KEY, clientId, username, 173 rhnServerTime, expireOffset) 174 if computed != signature: 175 log_debug(4, "Sent client signature %s does not match ours %s." % ( 176 signature, computed)) 177 raise rhnFault(33, "Invalid client session key") 178 179 # Convert the expiration/time to floats: 180 rhnServerTime = float(rhnServerTime) 181 expireOffset = float(expireOffset) 182 183 if rhnServerTime + expireOffset < time.time(): 184 log_debug(4, "Expired client authentication token") 185 raise rhnFault(34, "Expired client authentication token") 186 187 log_debug(4, "Client auth OK") 188 return 1
189