1 # Thierry Parmentelat -- INRIA
3 # a minimal library for writing "lightweight" SFA clients
8 import sfa.util.sfalogging
10 from sfa.client.sfaserverproxy import SfaServerProxy
12 # see optimizing dependencies below
13 from sfa.trust.certificate import Keypair, Certificate
16 # a helper class to implement the bootstrapping of crypto. material
17 # assuming we are starting from scratch on the client side
18 # what's needed to complete a full slice creation cycle
20 # (*) a local private key
21 # (*) the corresp. public key in the registry
22 # (**) step1: a self-signed certificate
23 # default filename is <hrn>.sscert
24 # (**) step2: a user credential
25 # obtained at the registry with GetSelfCredential
26 # using the self-signed certificate as the SSL cert
27 # default filename is <hrn>.user.cred
28 # (**) step3: a registry-provided certificate (i.e. a GID)
29 # obtained at the registry using Resolve
30 # using the step2 credential as credential
31 # default filename is <hrn>.user.gid
33 # from that point on, the GID can/should be used as the SSL cert for anything
34 # a new (slice) credential would be needed for slice operations and can be
35 # obtained at the registry through GetCredential
37 # xxx todo should protect against write file permissions
38 # xxx todo review exceptions
39 class SfaClientBootstrap:
41 # xxx todo should account for verbose and timeout that the proxy offers
42 def __init__ (self, user_hrn, registry_url, dir=None, logger=None):
44 self.registry_url=registry_url
45 if dir is None: dir="."
48 print 'special case for logger'
49 logger = sfa.util.sfalogging.logger
52 #################### public interface
54 # xxx should that be called in the constructor ?
55 # typically user_private_key is ~/.ssh/id_rsa
56 def init_private_key_if_missing (self, user_private_key):
57 private_key_filename=self.private_key_filename()
58 if not os.path.isfile (private_key_filename):
59 key=self.plain_read(user_private_key)
60 self.plain_write(private_key_filename, key)
61 os.chmod(private_key_filename,os.stat(user_private_key).st_mode)
62 self.logger.debug("SfaClientBootstrap: Copied private key from %s into %s"%\
63 (user_private_key,private_key_filename))
65 # make sure we have the GID at hand
66 def bootstrap_gid (self):
67 if self.any_certificate_filename() is None:
68 self.get_self_signed_cert()
72 def server_proxy (self, url):
73 return SfaServerProxy (url, self.private_key_filename(), self.gid_filename())
75 def get_credential_string (self):
76 return self.plain_read (self.get_credential())
78 # more to come to get credentials about other objects (authority/slice)
80 #################### private details
82 def fullpath (self, file): return os.path.join (self.dir,file)
84 def fullpath_format(self,format): return self.fullpath (format%self.hrn)
86 def private_key_filename (self):
87 return self.fullpath_format ("%s.pkey")
88 def self_signed_cert_filename (self):
89 return self.fullpath_format ("%s.sscert")
90 def credential_filename (self):
91 return self.fullpath_format ("%s.user.cred")
92 def gid_filename (self):
93 return self.fullpath_format ("%s.user.gid")
95 # optimizing dependencies
96 # originally we used classes GID or Credential or Certificate
98 # return Credential(filename=self.get_credential()).save_to_string()
99 # but in order to make it simpler to other implementations/languages..
100 def plain_read (self, filename):
101 infile=file(filename,"r")
106 def plain_write (self, filename, contents):
107 outfile=file(filename,"w")
108 result=outfile.write(contents)
112 def check_private_key (self):
113 if not os.path.isfile (self.private_key_filename()):
114 raise Exception,"No such file %s"%self.private_key_filename()
117 # get any certificate
118 # rationale for this method, once we have the gid, it's actually safe
119 # to remove the .sscert
120 def any_certificate_filename (self):
121 attempts=[ self.gid_filename(), self.self_signed_cert_filename() ]
122 for attempt in attempts:
123 if os.path.isfile (attempt): return attempt
128 def create_self_signed_certificate (self,output):
129 self.check_private_key()
130 private_key_filename = self.private_key_filename()
131 keypair=Keypair(filename=private_key_filename)
132 self_signed = Certificate (subject = self.hrn)
133 self_signed.set_pubkey (keypair)
134 self_signed.set_issuer (keypair, self.hrn)
136 self_signed.save_to_file (output)
137 self.logger.debug("SfaClientBootstrap: Created self-signed certificate for %s in %s"%\
141 def get_self_signed_cert (self):
142 self_signed_cert_filename = self.self_signed_cert_filename()
143 if os.path.isfile (self_signed_cert_filename):
144 return self_signed_cert_filename
145 return self.create_self_signed_certificate(self_signed_cert_filename)
149 def retrieve_credential (self, output):
150 self.check_private_key()
151 certificate_filename = self.any_certificate_filename()
152 certificate_string = self.plain_read (certificate_filename)
153 registry_proxy = SfaServerProxy (self.registry_url, self.private_key_filename(),
154 certificate_filename)
155 credential_string=registry_proxy.GetSelfCredential (certificate_string, self.hrn, "user")
156 self.plain_write (output, credential_string)
157 self.logger.debug("SfaClientBootstrap: Wrote result of GetSelfCredential in %s"%output)
160 def get_credential (self):
161 credential_filename = self.credential_filename ()
162 if os.path.isfile(credential_filename):
163 return credential_filename
164 return self.retrieve_credential (credential_filename)
168 def retrieve_gid (self, hrn, type, output):
169 self.check_private_key()
170 certificate_filename = self.any_certificate_filename()
171 registry_proxy = SfaServerProxy (self.registry_url, self.private_key_filename(),
172 certificate_filename)
173 credential_string=self.plain_read (self.get_credential())
174 records = registry_proxy.Resolve (hrn, credential_string)
175 records=[record for record in records if record['type']==type]
178 raise Exception, "hrn %s (%s) unknown to registry %s"%(hrn,type,self.registry_url)
180 self.plain_write (output, record['gid'])
181 self.logger.debug("SfaClientBootstrap: Wrote GID for %s (%s) in %s"% (hrn,type,output))
185 gid_filename=self.gid_filename()
186 if os.path.isfile(gid_filename):
188 return self.retrieve_gid(self.hrn, "user", gid_filename)