summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Paraskevopoulos <jpr@dialectics.space>2019-09-30 13:22:44 +0300
committerIvan Kanakarakis <ivan.kanak@gmail.com>2019-11-26 14:02:27 +0200
commitcc4526867734e40f3e413f309c450bb9033a871b (patch)
treea6caa568dd8138a3b818bedcf89b97fcc20955f1
parent2109a65b1a233d42da84cc2aad982bf8a4b49816 (diff)
downloadpysaml2-cc4526867734e40f3e413f309c450bb9033a871b.tar.gz
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`
-rw-r--r--docs/howto/config.rst24
-rw-r--r--src/saml2/config.py8
-rw-r--r--src/saml2/entity.py6
-rw-r--r--src/saml2/sigver.py79
-rw-r--r--tests/_test_80_p11_backend.py1
-rw-r--r--tests/test_40_sigver.py1
6 files changed, 71 insertions, 48 deletions
diff --git a/docs/howto/config.rst b/docs/howto/config.rst
index ddb41194..0e3be8a8 100644
--- a/docs/howto/config.rst
+++ b/docs/howto/config.rst
@@ -1,15 +1,5 @@
.. _howto_config:
-Environment variables
-=====================
-
-PYSAML2_DELETE_TMPFILES
-^^^^^^^^^^^^^^^^^^^^^^^
-
-If set to "False" will keep temporary xml files in the system temporary storage.
-Default: "true"; delete temporary files.
-
-
Configuration of pySAML2 entities
=================================
@@ -44,6 +34,7 @@ The basic structure of the configuration file is therefore like this::
"key_file" : "my.key",
"cert_file" : "ca.pem",
"xmlsec_binary" : "/usr/local/bin/xmlsec1",
+ "delete_tmpfiles": True,
"metadata": {
"local": ["edugain.xml"],
},
@@ -328,6 +319,17 @@ Example::
"xmlsec_binary": "/usr/local/bin/xmlsec1",
+delete_tmpfiles
+^^^^^^^^^^^^^^^
+
+In many cases temporary files will have to be created during the
+encryption/decryption/signing/validation process.
+This option defines whether these temporary files will be automatically deleted when
+they are no longer needed. Setting this to False, will keep these files until they are
+manually deleted or automatically deleted by the OS (i.e Linux rules for /tmp).
+Absence of this option, defaults to True.
+
+
valid_for
^^^^^^^^^
@@ -842,6 +844,7 @@ We start with a simple but fairly complete Service provider configuration::
"key_file" : "./mykey.pem",
"cert_file" : "./mycert.pem",
"xmlsec_binary" : "/usr/local/bin/xmlsec1",
+ "delete_tmpfiles": True,
"attribute_map_dir": "./attributemaps",
"metadata": {
"local": ["idp.xml"]
@@ -890,6 +893,7 @@ A slightly more complex configuration::
"key_file" : "./mykey.pem",
"cert_file" : "./mycert.pem",
"xmlsec_binary" : "/usr/local/bin/xmlsec1",
+ "delete_tmpfiles": True,
"metadata" : {
"local": ["example.xml"],
"remote": [{
diff --git a/src/saml2/config.py b/src/saml2/config.py
index 9b7debcb..274e3960 100644
--- a/src/saml2/config.py
+++ b/src/saml2/config.py
@@ -69,6 +69,7 @@ COMMON_ARGS = [
"allow_unknown_attributes",
"crypto_backend",
"id_attr_name",
+ "delete_tmpfiles",
]
SP_ARGS = [
@@ -243,6 +244,7 @@ class Config(object):
self.attribute = []
self.attribute_profile = []
self.requested_attribute_name_format = NAME_FORMAT_URI
+ self.delete_tmpfiles = True
def setattr(self, context, attr, val):
if context == "":
@@ -358,6 +360,12 @@ class Config(object):
except TypeError: # Something that can't be a string
setattr(self, arg, cnf[arg])
+ if not self.delete_tmpfiles:
+ logger.warning(
+ "delete_tmpfiles is set to False; "
+ "temporary files will not be deleted."
+ )
+
if "service" in cnf:
for typ in ["aa", "idp", "sp", "pdp", "aq"]:
try:
diff --git a/src/saml2/entity.py b/src/saml2/entity.py
index f76ae67d..2ab1995b 100644
--- a/src/saml2/entity.py
+++ b/src/saml2/entity.py
@@ -144,7 +144,7 @@ class Entity(HTTPBase):
if _val.startswith("http"):
r = requests.request("GET", _val)
if r.status_code == 200:
- tmp = make_temp(r.text, ".pem", False)
+ tmp = make_temp(r.text, ".pem", False, self.config.delete_tmpfiles)
setattr(self.config, item, tmp.name)
else:
raise Exception(
@@ -560,7 +560,9 @@ class Entity(HTTPBase):
_cert = "%s%s" % (begin_cert, _cert)
if end_cert not in _cert:
_cert = "%s%s" % (_cert, end_cert)
- tmp = make_temp(_cert.encode('ascii'), decode=False)
+ tmp = make_temp(_cert.encode('ascii'),
+ decode=False,
+ delete_tmpfiles=self.config.delete_tmpfiles)
response = self.sec.encrypt_assertion(response, tmp.name,
pre_encryption_part(),
node_xpath=node_xpath)
diff --git a/src/saml2/sigver.py b/src/saml2/sigver.py
index aaaa412c..cbeca41f 100644
--- a/src/saml2/sigver.py
+++ b/src/saml2/sigver.py
@@ -8,11 +8,9 @@ import hashlib
import itertools
import logging
import os
-import ssl
import six
from time import mktime
-from binascii import hexlify
from six.moves.urllib import parse
@@ -43,7 +41,6 @@ from saml2.s_utils import sid
from saml2.s_utils import Unsupported
from saml2.time_util import instant
-from saml2.time_util import utc_now
from saml2.time_util import str_to_time
from saml2.xmldsig import SIG_RSA_SHA1
@@ -195,7 +192,7 @@ def get_xmlsec_binary(paths=None):
raise SigverError('Cannot find {binary}'.format(binary=bin_name))
-def _get_xmlsec_cryptobackend(path=None, search_paths=None):
+def _get_xmlsec_cryptobackend(path=None, search_paths=None, delete_tmpfiles=True):
"""
Initialize a CryptoBackendXmlSec1 crypto backend.
@@ -203,7 +200,7 @@ def _get_xmlsec_cryptobackend(path=None, search_paths=None):
"""
if path is None:
path = get_xmlsec_binary(paths=search_paths)
- return CryptoBackendXmlSec1(path)
+ return CryptoBackendXmlSec1(path, delete_tmpfiles=delete_tmpfiles)
NODE_NAME = 'urn:oasis:names:tc:SAML:2.0:assertion:Assertion'
@@ -211,20 +208,6 @@ ENC_NODE_NAME = 'urn:oasis:names:tc:SAML:2.0:assertion:EncryptedAssertion'
ENC_KEY_CLASS = 'EncryptedKey'
-def get_environ_delete_tmpfiles():
- default = "true"
- value = os.environ.get("PYSAML2_DELETE_TMPFILES", default)
- result = value.lower() == default
-
- if not result:
- logger.warning(
- "PYSAML2_DELETE_TMPFILES set to False, "
- "temporary xml files will not be deleted."
- )
-
- return result
-
-
def _make_vals(val, klass, seccont, klass_inst=None, prop=None, part=False,
base64encode=False, elements_to_sign=None):
"""
@@ -336,7 +319,7 @@ def signed_instance_factory(instance, seccont, elements_to_sign=None):
return instance
-def make_temp(content, suffix="", decode=True):
+def make_temp(content, suffix="", decode=True, delete_tmpfiles=True):
"""
Create a temporary file with the given content.
@@ -348,6 +331,8 @@ def make_temp(content, suffix="", decode=True):
suffix in certain circumstances.
:param decode: The input content might be base64 coded. If so it
must, in some cases, be decoded before being placed in the file.
+ :param delete_tmpfiles: Whether to keep the tmp files or delete them when they are
+ no longer in use
:return: 2-tuple with file pointer ( so the calling function can
close the file) and filename (which is for instance needed by the
xmlsec function).
@@ -356,7 +341,6 @@ def make_temp(content, suffix="", decode=True):
content.encode("utf-8") if not isinstance(content, six.binary_type) else content
)
content_raw = base64.b64decode(content_encoded) if decode else content_encoded
- delete_tmpfiles = get_environ_delete_tmpfiles()
ntf = NamedTemporaryFile(suffix=suffix, delete=delete_tmpfiles)
ntf.write(content_raw)
ntf.seek(0)
@@ -689,11 +673,11 @@ class CryptoBackendXmlSec1(CryptoBackend):
__DEBUG = 0
- def __init__(self, xmlsec_binary, **kwargs):
+ def __init__(self, xmlsec_binary, delete_tmpfiles=True, **kwargs):
CryptoBackend.__init__(self, **kwargs)
assert (isinstance(xmlsec_binary, six.string_types))
self.xmlsec = xmlsec_binary
-
+ self.delete_tmpfiles = delete_tmpfiles
try:
self.non_xml_crypto = RSACrypto(kwargs['rsa_key'])
except KeyError:
@@ -721,7 +705,7 @@ class CryptoBackendXmlSec1(CryptoBackend):
:return:
"""
logger.debug('Encryption input len: %d', len(text))
- tmp = make_temp(text, decode=False)
+ tmp = make_temp(text, decode=False, delete_tmpfiles=self.delete_tmpfiles)
com_list = [
self.xmlsec,
'--encrypt',
@@ -758,8 +742,12 @@ class CryptoBackendXmlSec1(CryptoBackend):
if isinstance(statement, SamlBase):
statement = pre_encrypt_assertion(statement)
- tmp = make_temp(_str(statement), decode=False)
- tmp2 = make_temp(_str(template), decode=False)
+ tmp = make_temp(_str(statement),
+ decode=False,
+ delete_tmpfiles=self.delete_tmpfiles)
+ tmp2 = make_temp(_str(template),
+ decode=False,
+ delete_tmpfiles=self.delete_tmpfiles)
if not node_xpath:
node_xpath = ASSERT_XPATH
@@ -792,7 +780,7 @@ class CryptoBackendXmlSec1(CryptoBackend):
"""
logger.debug('Decrypt input len: %d', len(enctext))
- tmp = make_temp(enctext, decode=False)
+ tmp = make_temp(enctext, decode=False, delete_tmpfiles=self.delete_tmpfiles)
com_list = [
self.xmlsec,
@@ -824,7 +812,10 @@ class CryptoBackendXmlSec1(CryptoBackend):
if isinstance(statement, SamlBase):
statement = str(statement)
- tmp = make_temp(statement, suffix=".xml", decode=False)
+ tmp = make_temp(statement,
+ suffix=".xml",
+ decode=False,
+ delete_tmpfiles=self.delete_tmpfiles)
com_list = [
self.xmlsec,
@@ -865,7 +856,10 @@ class CryptoBackendXmlSec1(CryptoBackend):
if not isinstance(signedtext, six.binary_type):
signedtext = signedtext.encode('utf-8')
- tmp = make_temp(signedtext, suffix=".xml", decode=False)
+ tmp = make_temp(signedtext,
+ suffix=".xml",
+ decode=False,
+ delete_tmpfiles=self.delete_tmpfiles)
com_list = [
self.xmlsec,
@@ -1023,7 +1017,8 @@ def security_context(conf):
err_msg = err_msg.format(binary=xmlsec_binary)
raise SigverError(err_msg)
- crypto = _get_xmlsec_cryptobackend(xmlsec_binary)
+ crypto = _get_xmlsec_cryptobackend(xmlsec_binary,
+ delete_tmpfiles=conf.delete_tmpfiles)
_file_name = conf.getattr('key_file', '')
if _file_name:
@@ -1063,7 +1058,8 @@ def security_context(conf):
enc_key_files=enc_key_files,
encryption_keypairs=conf.encryption_keypairs,
sec_backend=sec_backend,
- id_attr=id_attr)
+ id_attr=id_attr,
+ delete_tmpfiles=conf.delete_tmpfiles)
def encrypt_cert_from_item(item):
@@ -1253,7 +1249,8 @@ class SecurityContext(object):
encryption_keypairs=None,
enc_cert_type='pem',
sec_backend=None,
- id_attr=''):
+ id_attr='',
+ delete_tmpfiles=True):
self.id_attr = id_attr or SecurityContext.DEFAULT_ID_ATTR_NAME
@@ -1304,6 +1301,7 @@ class SecurityContext(object):
self.template = template
self.encrypt_key_type = encrypt_key_type
+ self.delete_tmpfiles = delete_tmpfiles
def correctly_signed(self, xml, must=False):
logger.debug('verify correct signature')
@@ -1360,7 +1358,10 @@ class SecurityContext(object):
key.encode("ascii") if not isinstance(key, six.binary_type) else key
for key in keys_filtered
)
- key_files = list(make_temp(key, decode=False) for key in keys_encoded)
+ key_files = list(
+ make_temp(key, decode=False, delete_tmpfiles=self.delete_tmpfiles)
+ for key in keys_encoded
+ )
key_file_names = list(tmp.name for tmp in key_files)
try:
@@ -1450,7 +1451,10 @@ class SecurityContext(object):
for cert in _certs:
if isinstance(cert, six.string_types):
content = pem_format(cert)
- tmp = make_temp(content, suffix=".pem", decode=False)
+ tmp = make_temp(content,
+ suffix=".pem",
+ decode=False,
+ delete_tmpfiles=self.delete_tmpfiles)
certs.append(tmp)
else:
certs.append(cert)
@@ -1460,7 +1464,10 @@ class SecurityContext(object):
if not certs and not self.only_use_keys_in_metadata:
logger.debug('==== Certs from instance ====')
certs = [
- make_temp(content=pem_format(cert), suffix=".pem", decode=False)
+ make_temp(content=pem_format(cert),
+ suffix=".pem",
+ decode=False,
+ delete_tmpfiles=self.delete_tmpfiles)
for cert in cert_from_instance(item)
]
else:
@@ -1648,7 +1655,7 @@ class SecurityContext(object):
if not key_file and key:
content = str(key).encode()
- tmp = make_temp(content, suffix=".pem")
+ tmp = make_temp(content, suffix=".pem", delete_tmpfiles=self.delete_tmpfiles)
key_file = tmp.name
if not key and not key_file:
diff --git a/tests/_test_80_p11_backend.py b/tests/_test_80_p11_backend.py
index 218d1897..bdbb4fa6 100644
--- a/tests/_test_80_p11_backend.py
+++ b/tests/_test_80_p11_backend.py
@@ -63,6 +63,7 @@ class FakeConfig():
self.tmp_cert_file = None
self.tmp_key_file = None
self.validate_certificate = False
+ self.delete_tmpfiles = True
class TestPKCS11():
diff --git a/tests/test_40_sigver.py b/tests/test_40_sigver.py
index 89296dc0..07c919b7 100644
--- a/tests/test_40_sigver.py
+++ b/tests/test_40_sigver.py
@@ -128,6 +128,7 @@ class FakeConfig():
tmp_cert_file = None
tmp_key_file = None
validate_certificate = False
+ delete_tmpfiles = True
def getattr(self, attr, default):
return getattr(self, attr, default)