1 # ============LICENSE_START=======================================================
2 # Copyright (C) 2019 Nordix Foundation.
3 # ================================================================================
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 # SPDX-License-Identifier: Apache-2.0
17 # ============LICENSE_END=========================================================
31 log_file = '/opt/opendaylight/data/log/installCerts.log'
32 log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
33 logging.basicConfig(filename=log_file,level=logging.DEBUG,filemode='w',format=log_format)
39 username = os.environ['ODL_ADMIN_USERNAME']
40 password = os.environ['ODL_ADMIN_PASSWORD']
45 postKeystore= "/restconf/operations/netconf-keystore:add-keystore-entry"
46 postPrivateKey= "/restconf/operations/netconf-keystore:add-private-key"
47 postTrustedCertificate= "/restconf/operations/netconf-keystore:add-trusted-certificate"
49 truststore_pass_file = Path + '/truststore.pass'
50 truststore_file = Path + '/truststore.jks'
52 keystore_pass_file = Path + '/keystore.pass'
53 keystore_file = Path + '/keystore.jks'
55 jks_files = [truststore_pass_file, keystore_pass_file, keystore_file, truststore_file]
58 headers = {'Authorization':'Basic %s' % base64.b64encode(username + ":" + password),
59 'X-FromAppId': 'csit-sdnc',
60 'X-TransactionId': 'csit-sdnc',
61 'Accept':"application/json",
62 'Content-type':"application/json"}
65 def readFile(folder, file):
66 key = open(Path + "/" + folder + "/" + file, "r")
69 fileRead = "\n".join(fileRead.splitlines()[1:-1])
73 def readTrustedCertificate(folder, file):
77 key = open(folder + "/" + file, "r")
78 lines = key.readlines()
80 if not "BEGIN CERTIFICATE" in line and not "END CERTIFICATE" in line and startCa:
82 elif "BEGIN CERTIFICATE" in line:
84 elif "END CERTIFICATE" in line:
86 listCert.append(caPem)
91 def makeKeystoreKey(clientKey, count):
92 odl_private_key = "ODL_private_key_%d" %count
94 json_keystore_key='{{\"input\": {{ \"key-credential\": {{\"key-id\": \"{odl_private_key}\", \"private-key\" : ' \
95 '\"{clientKey}\",\"passphrase\" : \"\"}}}}}}'.format(
96 odl_private_key=odl_private_key,
99 return json_keystore_key
102 def makePrivateKey(clientKey, clientCrt, certList, count):
105 for cert in certList:
106 caPem += '\"%s\",' % cert
107 caPem = caPem.rsplit(',', 1)[0]
108 odl_private_key="ODL_private_key_%d" %count
110 json_private_key='{{\"input\": {{ \"private-key\":{{\"name\": \"{odl_private_key}\", \"data\" : ' \
111 '\"{clientKey}\",\"certificate-chain\":[\"{clientCrt}\",{caPem}]}}}}}}'.format(
112 odl_private_key=odl_private_key,
117 return json_private_key
120 def makeTrustedCertificate(certList, count):
122 json_cert_format = ""
123 for cert in certList:
124 cert_name = "xNF_CA_certificate_%d_%d" %(count, number)
125 json_cert_format += '{{\"name\": \"{trusted_name}\",\"certificate\":\"{cert}\"}},\n'.format(
126 trusted_name=cert_name,
130 json_cert_format = json_cert_format.rsplit(',', 1)[0]
131 json_trusted_cert='{{\"input\": {{ \"trusted-certificate\": [{certificates}]}}}}'.format(
132 certificates=json_cert_format)
133 return json_trusted_cert
136 def makeRestconfPost(conn, json_file, apiCall):
137 req = conn.request("POST", apiCall, json_file, headers=headers)
138 res = conn.getresponse()
140 if res.status != 200:
141 logging.error("Error here, response back wasnt 200: Response was : %d , %s" % (res.status, res.reason))
143 logging.debug("Response :%s Reason :%s ",res.status, res.reason)
146 def extractZipFiles(zipFileList, count):
147 for zipFolder in zipFileList:
148 with zipfile.ZipFile(Path + "/" + zipFolder.strip(),"r") as zip_ref:
149 zip_ref.extractall(Path)
150 folder = zipFolder.rsplit(".")[0]
151 processFiles(folder, count)
154 def processFiles(folder, count):
155 for file in os.listdir(Path + "/" + folder):
156 if os.path.isfile(Path + "/" + folder + "/" + file.strip()):
158 clientKey = readFile(folder, file.strip())
159 elif "trustedCertificate" in file:
160 certList = readTrustedCertificate(Path + "/" + folder, file.strip())
162 clientCrt = readFile(folder, file.strip())
164 logging.error("Could not find file %s" % file.strip())
165 shutil.rmtree(Path + "/" + folder)
166 post_content(clientKey, clientCrt, certList, count)
169 def post_content(clientKey, clientCrt, certList, count):
170 conn = httplib.HTTPConnection("localhost",odl_port)
173 json_keystore_key = makeKeystoreKey(clientKey, count)
174 logging.debug("Posting private key in to ODL keystore")
175 makeRestconfPost(conn, json_keystore_key, postKeystore)
178 json_trusted_cert = makeTrustedCertificate(certList, count)
179 logging.debug("Posting trusted cert list in to ODL")
180 makeRestconfPost(conn, json_trusted_cert, postTrustedCertificate)
182 if clientKey and clientCrt and certList:
183 json_private_key = makePrivateKey(clientKey, clientCrt, certList, count)
184 logging.debug("Posting the cert in to ODL")
185 makeRestconfPost(conn, json_private_key, postPrivateKey)
188 def makeHealthcheckCall(headers, timePassed):
190 # WAIT 10 minutes maximum and test every 30 seconds if HealthCheck API is returning 200
191 while timePassed < TIMEOUT:
193 conn = httplib.HTTPConnection("localhost",odl_port)
194 req = conn.request("POST", "/restconf/operations/SLI-API:healthcheck",headers=headers)
195 res = conn.getresponse()
197 if res.status == 200:
198 logging.debug("Healthcheck Passed in %d seconds." %timePassed)
202 logging.debug("Sleep: %d seconds before testing if Healthcheck worked. Total wait time up now is: %d seconds. Timeout is: %d seconds" %(INTERVAL, timePassed, TIMEOUT))
204 logging.error("Cannot execute REST call. Sleep: %d seconds before testing if Healthcheck worked. Total wait time up now is: %d seconds. Timeout is: %d seconds" %(INTERVAL, timePassed, TIMEOUT))
205 timePassed = timeIncrement(timePassed)
207 if timePassed > TIMEOUT:
208 logging.error("TIME OUT: Healthcheck not passed in %d seconds... Could cause problems for testing activities..." %TIMEOUT)
212 def timeIncrement(timePassed):
214 timePassed = timePassed + INTERVAL
218 def get_pass(file_name):
220 with open(file_name , 'r') as file_obj:
221 password = file_obj.read().strip()
223 except Exception as e:
224 logging.error("Error occurred while fetching password : %s", e)
229 for file in jks_files:
230 if os.path.isfile(file):
231 logging.debug("Cleaning up the file %s", file)
235 def jks_to_p12(file, password):
236 """Converts jks format into p12"""
238 p12_file = file.replace('.jks', '.p12')
239 jks_cmd = 'keytool -importkeystore -srckeystore {src_file} -destkeystore {dest_file} -srcstoretype JKS -srcstorepass {src_pass} -deststoretype PKCS12 -deststorepass {dest_pass}'.format(src_file=file, dest_file=p12_file, src_pass=password, dest_pass=password)
240 logging.debug("Converting %s into p12 format", file)
244 except Exception as e:
245 logging.error("Error occurred while converting jks to p12 format : %s", e)
248 def extract_content():
249 """Extracts client key, certificates, CA certificates."""
255 truststore_pass = get_pass(truststore_pass_file)
256 truststore_file_p12 = jks_to_p12(truststore_file, truststore_pass)
258 keystore_pass = get_pass(keystore_pass_file)
259 keystore_file_p12 = jks_to_p12(keystore_file, keystore_pass)
261 clcrt_cmd = 'openssl pkcs12 -in {src_file} -clcerts -nokeys -passin pass:{src_pass}'.format(src_file=keystore_file_p12, src_pass=keystore_pass)
263 clkey_cmd = 'openssl pkcs12 -in {src_file} -nocerts -nodes -passin pass:{src_pass}'.format(src_file=keystore_file_p12, src_pass=keystore_pass)
264 trust_file = truststore_file_p12.split('/')[2] + '.trust'
266 trustCerts_cmd = 'openssl pkcs12 -in {src_file} -out {out_file} -cacerts -nokeys -passin pass:{src_pass} '.format(src_file=truststore_file_p12, out_file=Path + '/' + trust_file, src_pass=truststore_pass)
268 result_key = subprocess.check_output(clkey_cmd , shell=True)
270 key = result_key.split('-----BEGIN PRIVATE KEY-----', 1)[1].lstrip().split('-----END PRIVATE KEY-----')[0]
271 logging.debug("key ok")
273 os.system(trustCerts_cmd)
274 if os.path.exists(Path + '/' + trust_file):
275 certList = readTrustedCertificate(Path, trust_file)
276 logging.debug("certList ok")
278 result_crt = subprocess.check_output(clcrt_cmd , shell=True)
280 cert = result_crt.split('-----BEGIN CERTIFICATE-----', 1)[1].lstrip().split('-----END CERTIFICATE-----')[0]
281 logging.debug("cert ok")
283 if key and cert and certList:
284 post_content(key, cert, certList, 0)
286 logging.debug("Exiting. Key, cert or key are missing")
289 except Exception as e:
290 logging.error("Error occurred while processing the file: %s", e)
293 def look_for_jks_files():
294 if all([os.path.isfile(f) for f in jks_files]):
298 logging.debug("Some of the files are missing")
302 def readCertProperties():
304 This function searches for manually copied zip file
305 containing certificates. This is required as part
306 of backward compatibility.
307 If not foud, it searches for jks certificates.
309 connected = makeHealthcheckCall(headers, timePassed)
313 if os.path.isfile(Path + "/certs.properties"):
314 with open(Path + "/certs.properties", "r") as f:
316 if not "*****" in line:
317 zipFileList.append(line)
319 extractZipFiles(zipFileList, count)
323 logging.debug("No zipfiles present in folder " + Path)
325 logging.info("Looking for jks files in folder " + Path)