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

Source Code for Module backend.server.rhnServer.server_certificate

  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  # Classes and functions needed for handling certificates 
 17  # The only really exportable item is the Certificate class 
 18  # 
 19   
 20  import sys 
 21  import hashlib 
 22  import time 
 23  import random 
 24  import socket 
 25  import string 
 26  try: 
 27      #  python 2 
 28      import xmlrpclib 
 29  except ImportError: 
 30      #  python3 
 31      import xmlrpc.client as xmlrpclib 
 32   
 33  from spacewalk.common.rhnLog import log_debug, log_error 
 34  from spacewalk.common.rhnException import rhnFault 
 35  from spacewalk.common.stringutils import to_string 
 36  from server_lib import getServerSecret 
 37   
 38   
39 -def gen_secret():
40 """ Generate a secret """ 41 seed = repr(time.time()) 42 sum = hashlib.new('sha256', seed) 43 # feed some random numbers 44 for k in range(1, random.randint(5, 15)): 45 sum.update(repr(random.random())) 46 sum.update(socket.gethostname()) 47 ret = "" 48 for i in sum.digest()[:]: 49 ret = ret + "%02x" % ord(i) 50 del sum 51 return ret
52 53
54 -class Checksum:
55 56 """ Functions for handling system_id strings """ 57
58 - def __init__(self, secret, *args, **kwargs):
59 algo = 'sha256' 60 if 'algo' in kwargs: 61 algo = kwargs['algo'] 62 self.sum = hashlib.new(algo, secret) 63 if len(args) > 0: 64 self.feed(*args)
65
66 - def feed(self, arg):
67 #sys.stderr.write("arg = %s, type = %s\n" % (arg, type(arg))) 68 if type(arg) == type(()) or type(arg) == type([]): 69 for s in arg: 70 self.sum.update(s) 71 else: 72 if type(arg) == type(0): 73 arg = str(arg) 74 self.sum.update(to_string(arg))
75
76 - def __repr__(self):
77 t = "" 78 for i in self.sum.digest()[:]: 79 t = t + "%02x" % ord(i) 80 return t
81 __str__ = __repr__
82 83
84 -class Certificate:
85 86 """ Main certificate class """ 87 CheckSumFields = ["username", "os_release", "operating_system", 88 "architecture", "system_id", "type"] 89
90 - def __init__(self):
91 """ init data 92 normally we include in the attrs: 93 username, os_release, os, arch, system_id and fields 94 """ 95 self.attrs = {} 96 for k in Certificate.CheckSumFields: 97 self.attrs[k] = None 98 self.__fields = [] 99 self.__secret = None 100 self.__checksum = None
101
102 - def __getitem__(self, key):
103 """ function that make it look like a dictionary for easy access """ 104 return self.attrs.get(key)
105
106 - def __setitem__(self, name, value):
107 """ function that make it look like a dictionary for easy access 108 updates the values of the attributes list with new values 109 """ 110 self.attrs[name] = value 111 if name in Certificate.CheckSumFields: 112 if name not in self.__fields: 113 self.__fields.append(name) 114 else: # non essential, take None values as "" 115 if value is None: 116 self.attrs[name] = "" 117 return 0
118
119 - def __repr__(self):
120 """ string format """ 121 return "<Certificate instance>: Attrs: %s, Fields: %s, Secret: %s, Checksum: %s" % ( 122 self.attrs, self.__fields, self.__secret, self.__checksum)
123 __str__ = __repr__ 124
125 - def certificate(self):
126 """ convert to XML """ 127 dump = self.attrs 128 dump["checksum"] = self.__checksum 129 dump["fields"] = self.__fields 130 try: 131 x = xmlrpclib.dumps((dump,)) 132 except TypeError: 133 e = sys.exc_info()[1] 134 log_error("Could not marshall certificate for %s" % dump) 135 e.args = e.args + (dump,) # Carry on the information for the exception reporting 136 raise 137 return '<?xml version="1.0"?>\n%s' % x
138
139 - def compute_checksum(self, secret, algo='sha256'):
140 """ Update the checksum """ 141 log_debug(4, secret, self.attrs) 142 csum = Checksum(secret, algo=algo) 143 for f in self.__fields: 144 csum.feed(self.attrs[f]) 145 # feed the fields list last 146 csum.feed(self.__fields) 147 return str(csum)
148
149 - def set_secret(self, secret):
150 """ set the secret of the entry and recompute the checksum """ 151 log_debug(4, "secret", secret) 152 self.__secret = secret 153 self.__checksum = self.compute_checksum(secret)
154
155 - def reload(self, text):
156 """ load data from a text certificate passed on by a client """ 157 log_debug(4) 158 text_id = string.strip(text) 159 if not text_id: 160 return -1 161 # Now decode this certificate 162 try: 163 sysid, junk = xmlrpclib.loads(to_string(text_id)) 164 except: 165 return -1 166 else: 167 s = sysid[0] 168 del junk 169 if "system_id" not in s or not s.has_key("fields"): 170 log_error("Got certificate with missing entries: %s" % s) 171 return -1 172 # check the certificate some more 173 for k in s["fields"]: 174 if k not in s: 175 log_error("Certificate lists unknown %s as a checksum field" % k, 176 "cert data: %s" % s) 177 return -1 178 179 # clear out the state 180 self.__init__() 181 182 # at this point we know the certificate is sane enough for the 183 # following processing 184 for k in s.keys(): 185 if k == "fields": 186 self.__fields = s[k] 187 continue 188 if k == "checksum": 189 self.__checksum = s[k] 190 continue 191 self.attrs[k] = s[k] 192 # okay, the certificate is now loaded 193 return 0
194
195 - def __validate_checksum(self, secret):
196 """ compute the current checksum against a secret and check it against 197 the current checksum 198 """ 199 if len(secret) == 64: 200 csum = self.compute_checksum(secret, algo='sha256') 201 elif len(secret) == 32: 202 csum = self.compute_checksum(secret, algo='md5') 203 if not csum == self.__checksum: 204 # fail, current checksum does not match 205 log_error("Checksum check failed: %s != %s" % (csum, self.__checksum), 206 "fields = %s" % str(self.__fields), "attrs = %s" % str(self.attrs)) 207 return 0 208 return 1
209
210 - def valid(self):
211 log_debug(4) 212 # check for anonymous 213 if 'type' in self.attrs and self.attrs['type'] \ 214 and string.upper(self.attrs['type']) == "ANONYMOUS": 215 raise rhnFault(28, """ 216 You need to re-register your system with Red Hat Satellite. 217 Previously you have chosen to skip the creation of a system profile 218 with Red Hat Satellite and this trial feature is no longer available now. 219 """) # we don't support anonymous anymore 220 # now we have a real server. Get its secret 221 sid = self.attrs["system_id"] 222 secret = getServerSecret(sid) 223 if secret is None: 224 # no secret, can't validate 225 log_debug(1, "Server id %s not found in database" % sid) 226 return 0 227 return self.__validate_checksum(secret)
228