Atomic write of certificate files and revocation list
Using a rename from a temporary file to avoid having partial writes. Closes-Bug: #1285833 Change-Id: I3e70c795be357ceab8e5a1d12202c04fd88a02b8
This commit is contained in:

committed by
Dolph Mathews

parent
19356011e6
commit
b935741f6c
@@ -1324,6 +1324,24 @@ class AuthProtocol(object):
|
|||||||
self.token_revocation_list = self.fetch_revocation_list()
|
self.token_revocation_list = self.fetch_revocation_list()
|
||||||
return self._token_revocation_list
|
return self._token_revocation_list
|
||||||
|
|
||||||
|
def _atomic_write_to_signing_dir(self, file_name, value):
|
||||||
|
# In Python2, encoding is slow so the following check avoids it if it
|
||||||
|
# is not absolutely necessary.
|
||||||
|
if isinstance(value, six.text_type):
|
||||||
|
value = value.encode('utf-8')
|
||||||
|
|
||||||
|
def _atomic_write(destination, data):
|
||||||
|
with tempfile.NamedTemporaryFile(dir=self.signing_dirname,
|
||||||
|
delete=False) as f:
|
||||||
|
f.write(data)
|
||||||
|
os.rename(f.name, destination)
|
||||||
|
|
||||||
|
try:
|
||||||
|
_atomic_write(file_name, value)
|
||||||
|
except (OSError, IOError):
|
||||||
|
self.verify_signing_dir()
|
||||||
|
_atomic_write(file_name, value)
|
||||||
|
|
||||||
@token_revocation_list.setter
|
@token_revocation_list.setter
|
||||||
def token_revocation_list(self, value):
|
def token_revocation_list(self, value):
|
||||||
"""Save a revocation list to memory and to disk.
|
"""Save a revocation list to memory and to disk.
|
||||||
@@ -1333,15 +1351,7 @@ class AuthProtocol(object):
|
|||||||
"""
|
"""
|
||||||
self._token_revocation_list = jsonutils.loads(value)
|
self._token_revocation_list = jsonutils.loads(value)
|
||||||
self.token_revocation_list_fetched_time = timeutils.utcnow()
|
self.token_revocation_list_fetched_time = timeutils.utcnow()
|
||||||
|
self._atomic_write_to_signing_dir(self.revoked_file_name, value)
|
||||||
with tempfile.NamedTemporaryFile(dir=self.signing_dirname,
|
|
||||||
delete=False) as f:
|
|
||||||
# In Python2, encoding is slow so the following check avoids it if
|
|
||||||
# it is not absolutely necessary.
|
|
||||||
if isinstance(value, six.text_type):
|
|
||||||
value = value.encode('utf-8')
|
|
||||||
f.write(value)
|
|
||||||
os.rename(f.name, self.revoked_file_name)
|
|
||||||
|
|
||||||
def fetch_revocation_list(self, retry=True):
|
def fetch_revocation_list(self, retry=True):
|
||||||
headers = {'X-Auth-Token': self.get_admin_token()}
|
headers = {'X-Auth-Token': self.get_admin_token()}
|
||||||
@@ -1360,42 +1370,18 @@ class AuthProtocol(object):
|
|||||||
raise ServiceError('Revocation list improperly formatted.')
|
raise ServiceError('Revocation list improperly formatted.')
|
||||||
return self.cms_verify(data['signed'])
|
return self.cms_verify(data['signed'])
|
||||||
|
|
||||||
def fetch_signing_cert(self):
|
def _fetch_cert_file(self, cert_file_name, cert_type):
|
||||||
path = '/v2.0/certificates/signing'
|
path = '/v2.0/certificates/' + cert_type
|
||||||
response = self._http_request('GET', path)
|
response = self._http_request('GET', path)
|
||||||
|
|
||||||
def write_cert_file(data):
|
|
||||||
with open(self.signing_cert_file_name, 'w') as certfile:
|
|
||||||
certfile.write(data)
|
|
||||||
|
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
raise exceptions.CertificateConfigError(response.text)
|
raise exceptions.CertificateConfigError(response.text)
|
||||||
|
self._atomic_write_to_signing_dir(cert_file_name, response.text)
|
||||||
|
|
||||||
try:
|
def fetch_signing_cert(self):
|
||||||
try:
|
self._fetch_cert_file(self.signing_cert_file_name, 'signing')
|
||||||
write_cert_file(response.text)
|
|
||||||
except IOError:
|
|
||||||
self.verify_signing_dir()
|
|
||||||
write_cert_file(response.text)
|
|
||||||
except (AssertionError, KeyError):
|
|
||||||
self.LOG.warn(
|
|
||||||
"Unexpected response from keystone service: %s", response.text)
|
|
||||||
raise ServiceError('invalid json response')
|
|
||||||
|
|
||||||
def fetch_ca_cert(self):
|
def fetch_ca_cert(self):
|
||||||
path = '/v2.0/certificates/ca'
|
self._fetch_cert_file(self.signing_ca_file_name, 'ca')
|
||||||
response = self._http_request('GET', path)
|
|
||||||
|
|
||||||
if response.status_code != 200:
|
|
||||||
raise exceptions.CertificateConfigError(response.text)
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(self.signing_ca_file_name, 'w') as certfile:
|
|
||||||
certfile.write(response.text)
|
|
||||||
except (AssertionError, KeyError):
|
|
||||||
self.LOG.warn(
|
|
||||||
"Unexpected response from keystone service: %s", response.text)
|
|
||||||
raise ServiceError('invalid json response')
|
|
||||||
|
|
||||||
|
|
||||||
def filter_factory(global_conf, **local_conf):
|
def filter_factory(global_conf, **local_conf):
|
||||||
|
Reference in New Issue
Block a user