Skip to content

Commit cc45268

Browse files
ioparaskevc00kiemon5ter
authored andcommitted
Extract PYSAML2_DELETE_TMPFILES option to config.py
- Moves parsing PYSAML2_DELETE_TMPFILES option to config.py and uses the value as a Config class property (`delete_tmpfiles`). This attribute is part of the configuration so its place is in the config.py and the corresponding class. This may add the config object dependency to classes/functions that are calling the `make_temp` function, but at the same time keeps a more layered approach since this config option is now processed and set up in the correct layer; that is the Config class and the config module. Scripts that (in)directly use classes that have methods that use the `make_temp` functions were not changed since those methods are not called when these scripts run and they are out of the scripts' scope (that is, the script functionality does not create any temp file). Those scripts are `verify_metadata`, `merge_metadata` and `mdexport`
1 parent 2109a65 commit cc45268

File tree

6 files changed

+71
-48
lines changed

6 files changed

+71
-48
lines changed

docs/howto/config.rst

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
.. _howto_config:
22

3-
Environment variables
4-
=====================
5-
6-
PYSAML2_DELETE_TMPFILES
7-
^^^^^^^^^^^^^^^^^^^^^^^
8-
9-
If set to "False" will keep temporary xml files in the system temporary storage.
10-
Default: "true"; delete temporary files.
11-
12-
133
Configuration of pySAML2 entities
144
=================================
155

@@ -44,6 +34,7 @@ The basic structure of the configuration file is therefore like this::
4434
"key_file" : "my.key",
4535
"cert_file" : "ca.pem",
4636
"xmlsec_binary" : "/usr/local/bin/xmlsec1",
37+
"delete_tmpfiles": True,
4738
"metadata": {
4839
"local": ["edugain.xml"],
4940
},
@@ -328,6 +319,17 @@ Example::
328319

329320
"xmlsec_binary": "/usr/local/bin/xmlsec1",
330321

322+
delete_tmpfiles
323+
^^^^^^^^^^^^^^^
324+
325+
In many cases temporary files will have to be created during the
326+
encryption/decryption/signing/validation process.
327+
This option defines whether these temporary files will be automatically deleted when
328+
they are no longer needed. Setting this to False, will keep these files until they are
329+
manually deleted or automatically deleted by the OS (i.e Linux rules for /tmp).
330+
Absence of this option, defaults to True.
331+
332+
331333
valid_for
332334
^^^^^^^^^
333335

@@ -842,6 +844,7 @@ We start with a simple but fairly complete Service provider configuration::
842844
"key_file" : "./mykey.pem",
843845
"cert_file" : "./mycert.pem",
844846
"xmlsec_binary" : "/usr/local/bin/xmlsec1",
847+
"delete_tmpfiles": True,
845848
"attribute_map_dir": "./attributemaps",
846849
"metadata": {
847850
"local": ["idp.xml"]
@@ -890,6 +893,7 @@ A slightly more complex configuration::
890893
"key_file" : "./mykey.pem",
891894
"cert_file" : "./mycert.pem",
892895
"xmlsec_binary" : "/usr/local/bin/xmlsec1",
896+
"delete_tmpfiles": True,
893897
"metadata" : {
894898
"local": ["example.xml"],
895899
"remote": [{

src/saml2/config.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"allow_unknown_attributes",
7070
"crypto_backend",
7171
"id_attr_name",
72+
"delete_tmpfiles",
7273
]
7374

7475
SP_ARGS = [
@@ -243,6 +244,7 @@ def __init__(self, homedir="."):
243244
self.attribute = []
244245
self.attribute_profile = []
245246
self.requested_attribute_name_format = NAME_FORMAT_URI
247+
self.delete_tmpfiles = True
246248

247249
def setattr(self, context, attr, val):
248250
if context == "":
@@ -358,6 +360,12 @@ def load(self, cnf, metadata_construction=False):
358360
except TypeError: # Something that can't be a string
359361
setattr(self, arg, cnf[arg])
360362

363+
if not self.delete_tmpfiles:
364+
logger.warning(
365+
"delete_tmpfiles is set to False; "
366+
"temporary files will not be deleted."
367+
)
368+
361369
if "service" in cnf:
362370
for typ in ["aa", "idp", "sp", "pdp", "aq"]:
363371
try:

src/saml2/entity.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def __init__(self, entity_type, config=None, config_file="",
144144
if _val.startswith("http"):
145145
r = requests.request("GET", _val)
146146
if r.status_code == 200:
147-
tmp = make_temp(r.text, ".pem", False)
147+
tmp = make_temp(r.text, ".pem", False, self.config.delete_tmpfiles)
148148
setattr(self.config, item, tmp.name)
149149
else:
150150
raise Exception(
@@ -560,7 +560,9 @@ def _encrypt_assertion(self, encrypt_cert, sp_entity_id, response,
560560
_cert = "%s%s" % (begin_cert, _cert)
561561
if end_cert not in _cert:
562562
_cert = "%s%s" % (_cert, end_cert)
563-
tmp = make_temp(_cert.encode('ascii'), decode=False)
563+
tmp = make_temp(_cert.encode('ascii'),
564+
decode=False,
565+
delete_tmpfiles=self.config.delete_tmpfiles)
564566
response = self.sec.encrypt_assertion(response, tmp.name,
565567
pre_encryption_part(),
566568
node_xpath=node_xpath)

src/saml2/sigver.py

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88
import itertools
99
import logging
1010
import os
11-
import ssl
1211
import six
1312

1413
from time import mktime
15-
from binascii import hexlify
1614

1715
from six.moves.urllib import parse
1816

@@ -43,7 +41,6 @@
4341
from saml2.s_utils import Unsupported
4442

4543
from saml2.time_util import instant
46-
from saml2.time_util import utc_now
4744
from saml2.time_util import str_to_time
4845

4946
from saml2.xmldsig import SIG_RSA_SHA1
@@ -195,36 +192,22 @@ def get_xmlsec_binary(paths=None):
195192
raise SigverError('Cannot find {binary}'.format(binary=bin_name))
196193

197194

198-
def _get_xmlsec_cryptobackend(path=None, search_paths=None):
195+
def _get_xmlsec_cryptobackend(path=None, search_paths=None, delete_tmpfiles=True):
199196
"""
200197
Initialize a CryptoBackendXmlSec1 crypto backend.
201198
202199
This function is now internal to this module.
203200
"""
204201
if path is None:
205202
path = get_xmlsec_binary(paths=search_paths)
206-
return CryptoBackendXmlSec1(path)
203+
return CryptoBackendXmlSec1(path, delete_tmpfiles=delete_tmpfiles)
207204

208205

209206
NODE_NAME = 'urn:oasis:names:tc:SAML:2.0:assertion:Assertion'
210207
ENC_NODE_NAME = 'urn:oasis:names:tc:SAML:2.0:assertion:EncryptedAssertion'
211208
ENC_KEY_CLASS = 'EncryptedKey'
212209

213210

214-
def get_environ_delete_tmpfiles():
215-
default = "true"
216-
value = os.environ.get("PYSAML2_DELETE_TMPFILES", default)
217-
result = value.lower() == default
218-
219-
if not result:
220-
logger.warning(
221-
"PYSAML2_DELETE_TMPFILES set to False, "
222-
"temporary xml files will not be deleted."
223-
)
224-
225-
return result
226-
227-
228211
def _make_vals(val, klass, seccont, klass_inst=None, prop=None, part=False,
229212
base64encode=False, elements_to_sign=None):
230213
"""
@@ -336,7 +319,7 @@ def signed_instance_factory(instance, seccont, elements_to_sign=None):
336319
return instance
337320

338321

339-
def make_temp(content, suffix="", decode=True):
322+
def make_temp(content, suffix="", decode=True, delete_tmpfiles=True):
340323
"""
341324
Create a temporary file with the given content.
342325
@@ -348,6 +331,8 @@ def make_temp(content, suffix="", decode=True):
348331
suffix in certain circumstances.
349332
:param decode: The input content might be base64 coded. If so it
350333
must, in some cases, be decoded before being placed in the file.
334+
:param delete_tmpfiles: Whether to keep the tmp files or delete them when they are
335+
no longer in use
351336
:return: 2-tuple with file pointer ( so the calling function can
352337
close the file) and filename (which is for instance needed by the
353338
xmlsec function).
@@ -356,7 +341,6 @@ def make_temp(content, suffix="", decode=True):
356341
content.encode("utf-8") if not isinstance(content, six.binary_type) else content
357342
)
358343
content_raw = base64.b64decode(content_encoded) if decode else content_encoded
359-
delete_tmpfiles = get_environ_delete_tmpfiles()
360344
ntf = NamedTemporaryFile(suffix=suffix, delete=delete_tmpfiles)
361345
ntf.write(content_raw)
362346
ntf.seek(0)
@@ -689,11 +673,11 @@ class CryptoBackendXmlSec1(CryptoBackend):
689673

690674
__DEBUG = 0
691675

692-
def __init__(self, xmlsec_binary, **kwargs):
676+
def __init__(self, xmlsec_binary, delete_tmpfiles=True, **kwargs):
693677
CryptoBackend.__init__(self, **kwargs)
694678
assert (isinstance(xmlsec_binary, six.string_types))
695679
self.xmlsec = xmlsec_binary
696-
680+
self.delete_tmpfiles = delete_tmpfiles
697681
try:
698682
self.non_xml_crypto = RSACrypto(kwargs['rsa_key'])
699683
except KeyError:
@@ -721,7 +705,7 @@ def encrypt(self, text, recv_key, template, session_key_type, xpath=''):
721705
:return:
722706
"""
723707
logger.debug('Encryption input len: %d', len(text))
724-
tmp = make_temp(text, decode=False)
708+
tmp = make_temp(text, decode=False, delete_tmpfiles=self.delete_tmpfiles)
725709
com_list = [
726710
self.xmlsec,
727711
'--encrypt',
@@ -758,8 +742,12 @@ def encrypt_assertion(self, statement, enc_key, template, key_type='des-192', no
758742
if isinstance(statement, SamlBase):
759743
statement = pre_encrypt_assertion(statement)
760744

761-
tmp = make_temp(_str(statement), decode=False)
762-
tmp2 = make_temp(_str(template), decode=False)
745+
tmp = make_temp(_str(statement),
746+
decode=False,
747+
delete_tmpfiles=self.delete_tmpfiles)
748+
tmp2 = make_temp(_str(template),
749+
decode=False,
750+
delete_tmpfiles=self.delete_tmpfiles)
763751

764752
if not node_xpath:
765753
node_xpath = ASSERT_XPATH
@@ -792,7 +780,7 @@ def decrypt(self, enctext, key_file, id_attr):
792780
"""
793781

794782
logger.debug('Decrypt input len: %d', len(enctext))
795-
tmp = make_temp(enctext, decode=False)
783+
tmp = make_temp(enctext, decode=False, delete_tmpfiles=self.delete_tmpfiles)
796784

797785
com_list = [
798786
self.xmlsec,
@@ -824,7 +812,10 @@ def sign_statement(self, statement, node_name, key_file, node_id, id_attr):
824812
if isinstance(statement, SamlBase):
825813
statement = str(statement)
826814

827-
tmp = make_temp(statement, suffix=".xml", decode=False)
815+
tmp = make_temp(statement,
816+
suffix=".xml",
817+
decode=False,
818+
delete_tmpfiles=self.delete_tmpfiles)
828819

829820
com_list = [
830821
self.xmlsec,
@@ -865,7 +856,10 @@ def validate_signature(self, signedtext, cert_file, cert_type, node_name, node_i
865856
if not isinstance(signedtext, six.binary_type):
866857
signedtext = signedtext.encode('utf-8')
867858

868-
tmp = make_temp(signedtext, suffix=".xml", decode=False)
859+
tmp = make_temp(signedtext,
860+
suffix=".xml",
861+
decode=False,
862+
delete_tmpfiles=self.delete_tmpfiles)
869863

870864
com_list = [
871865
self.xmlsec,
@@ -1023,7 +1017,8 @@ def security_context(conf):
10231017
err_msg = err_msg.format(binary=xmlsec_binary)
10241018
raise SigverError(err_msg)
10251019

1026-
crypto = _get_xmlsec_cryptobackend(xmlsec_binary)
1020+
crypto = _get_xmlsec_cryptobackend(xmlsec_binary,
1021+
delete_tmpfiles=conf.delete_tmpfiles)
10271022

10281023
_file_name = conf.getattr('key_file', '')
10291024
if _file_name:
@@ -1063,7 +1058,8 @@ def security_context(conf):
10631058
enc_key_files=enc_key_files,
10641059
encryption_keypairs=conf.encryption_keypairs,
10651060
sec_backend=sec_backend,
1066-
id_attr=id_attr)
1061+
id_attr=id_attr,
1062+
delete_tmpfiles=conf.delete_tmpfiles)
10671063

10681064

10691065
def encrypt_cert_from_item(item):
@@ -1253,7 +1249,8 @@ def __init__(
12531249
encryption_keypairs=None,
12541250
enc_cert_type='pem',
12551251
sec_backend=None,
1256-
id_attr=''):
1252+
id_attr='',
1253+
delete_tmpfiles=True):
12571254

12581255
self.id_attr = id_attr or SecurityContext.DEFAULT_ID_ATTR_NAME
12591256

@@ -1304,6 +1301,7 @@ def __init__(
13041301
self.template = template
13051302

13061303
self.encrypt_key_type = encrypt_key_type
1304+
self.delete_tmpfiles = delete_tmpfiles
13071305

13081306
def correctly_signed(self, xml, must=False):
13091307
logger.debug('verify correct signature')
@@ -1360,7 +1358,10 @@ def decrypt_keys(self, enctext, keys=None, id_attr=''):
13601358
key.encode("ascii") if not isinstance(key, six.binary_type) else key
13611359
for key in keys_filtered
13621360
)
1363-
key_files = list(make_temp(key, decode=False) for key in keys_encoded)
1361+
key_files = list(
1362+
make_temp(key, decode=False, delete_tmpfiles=self.delete_tmpfiles)
1363+
for key in keys_encoded
1364+
)
13641365
key_file_names = list(tmp.name for tmp in key_files)
13651366

13661367
try:
@@ -1450,7 +1451,10 @@ def _check_signature(self, decoded_xml, item, node_name=NODE_NAME, origdoc=None,
14501451
for cert in _certs:
14511452
if isinstance(cert, six.string_types):
14521453
content = pem_format(cert)
1453-
tmp = make_temp(content, suffix=".pem", decode=False)
1454+
tmp = make_temp(content,
1455+
suffix=".pem",
1456+
decode=False,
1457+
delete_tmpfiles=self.delete_tmpfiles)
14541458
certs.append(tmp)
14551459
else:
14561460
certs.append(cert)
@@ -1460,7 +1464,10 @@ def _check_signature(self, decoded_xml, item, node_name=NODE_NAME, origdoc=None,
14601464
if not certs and not self.only_use_keys_in_metadata:
14611465
logger.debug('==== Certs from instance ====')
14621466
certs = [
1463-
make_temp(content=pem_format(cert), suffix=".pem", decode=False)
1467+
make_temp(content=pem_format(cert),
1468+
suffix=".pem",
1469+
decode=False,
1470+
delete_tmpfiles=self.delete_tmpfiles)
14641471
for cert in cert_from_instance(item)
14651472
]
14661473
else:
@@ -1648,7 +1655,7 @@ def sign_statement(self, statement, node_name, key=None, key_file=None, node_id=
16481655

16491656
if not key_file and key:
16501657
content = str(key).encode()
1651-
tmp = make_temp(content, suffix=".pem")
1658+
tmp = make_temp(content, suffix=".pem", delete_tmpfiles=self.delete_tmpfiles)
16521659
key_file = tmp.name
16531660

16541661
if not key and not key_file:

tests/_test_80_p11_backend.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def __init__(self, pub_key = PUB_KEY):
6363
self.tmp_cert_file = None
6464
self.tmp_key_file = None
6565
self.validate_certificate = False
66+
self.delete_tmpfiles = True
6667

6768

6869
class TestPKCS11():

tests/test_40_sigver.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class FakeConfig():
128128
tmp_cert_file = None
129129
tmp_key_file = None
130130
validate_certificate = False
131+
delete_tmpfiles = True
131132

132133
def getattr(self, attr, default):
133134
return getattr(self, attr, default)

0 commit comments

Comments
 (0)