whitespace
This commit is contained in:
@@ -76,7 +76,7 @@ def signed(item):
|
||||
def get_xmlsec_binary(paths=None):
|
||||
"""
|
||||
Tries to find the xmlsec1 binary.
|
||||
|
||||
|
||||
:param paths: Non-system path paths which should be searched when
|
||||
looking for xmlsec1
|
||||
:return: full name of the xmlsec1 binary found. If no binaries are
|
||||
@@ -107,12 +107,12 @@ def get_xmlsec_binary(paths=None):
|
||||
pass
|
||||
|
||||
raise Exception("Can't find %s" % bin_name)
|
||||
|
||||
|
||||
try:
|
||||
XMLSEC_BINARY = get_xmlsec_binary()
|
||||
except Exception:
|
||||
XMLSEC_BINARY = ""
|
||||
|
||||
|
||||
ID_ATTR = "ID"
|
||||
NODE_NAME = "urn:oasis:names:tc:SAML:2.0:assertion:Assertion"
|
||||
ENC_NODE_NAME = "urn:oasis:names:tc:SAML:2.0:assertion:EncryptedAssertion"
|
||||
@@ -153,10 +153,10 @@ def _make_vals(val, klass, seccont, klass_inst=None, prop=None, part=False,
|
||||
"""
|
||||
Creates a class instance with a specified value, the specified
|
||||
class instance may be a value on a property in a defined class instance.
|
||||
|
||||
|
||||
:param val: The value
|
||||
:param klass: The value class
|
||||
:param klass_inst: The class instance which has a property on which
|
||||
:param klass_inst: The class instance which has a property on which
|
||||
what this function returns is a value.
|
||||
:param prop: The property which the value should be assigned to.
|
||||
:param part: If the value is one of a possible list of values it should be
|
||||
@@ -166,7 +166,7 @@ def _make_vals(val, klass, seccont, klass_inst=None, prop=None, part=False,
|
||||
cinst = None
|
||||
|
||||
#print "make_vals(%s, %s)" % (val, klass)
|
||||
|
||||
|
||||
if isinstance(val, dict):
|
||||
cinst = _instance(klass, val, seccont, base64encode=base64encode,
|
||||
elements_to_sign=elements_to_sign)
|
||||
@@ -175,23 +175,23 @@ def _make_vals(val, klass, seccont, klass_inst=None, prop=None, part=False,
|
||||
cinst = klass().set_text(val)
|
||||
except ValueError:
|
||||
if not part:
|
||||
cis = [_make_vals(sval, klass, seccont, klass_inst, prop,
|
||||
cis = [_make_vals(sval, klass, seccont, klass_inst, prop,
|
||||
True, base64encode, elements_to_sign) for sval in val]
|
||||
setattr(klass_inst, prop, cis)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
if part:
|
||||
return cinst
|
||||
else:
|
||||
if cinst:
|
||||
else:
|
||||
if cinst:
|
||||
cis = [cinst]
|
||||
setattr(klass_inst, prop, cis)
|
||||
|
||||
|
||||
|
||||
def _instance(klass, ava, seccont, base64encode=False, elements_to_sign=None):
|
||||
instance = klass()
|
||||
|
||||
|
||||
for prop in instance.c_attributes.values():
|
||||
#print "# %s" % (prop)
|
||||
if prop in ava:
|
||||
@@ -204,7 +204,7 @@ def _instance(klass, ava, seccont, base64encode=False, elements_to_sign=None):
|
||||
|
||||
if "text" in ava:
|
||||
instance.set_text(ava["text"], base64encode)
|
||||
|
||||
|
||||
for prop, klassdef in instance.c_children.values():
|
||||
#print "## %s, %s" % (prop, klassdef)
|
||||
if prop in ava:
|
||||
@@ -223,14 +223,14 @@ def _instance(klass, ava, seccont, base64encode=False, elements_to_sign=None):
|
||||
for item in ava["extension_elements"]:
|
||||
instance.extension_elements.append(
|
||||
ExtensionElement(item["tag"]).loadd(item))
|
||||
|
||||
|
||||
if "extension_attributes" in ava:
|
||||
for key, val in ava["extension_attributes"].items():
|
||||
instance.extension_attributes[key] = val
|
||||
|
||||
if "signature" in ava:
|
||||
elements_to_sign.append((class_name(instance), instance.id))
|
||||
|
||||
elements_to_sign.append((class_name(instance), instance.id))
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
@@ -259,29 +259,29 @@ def signed_instance_factory(instance, seccont, elements_to_sign=None):
|
||||
|
||||
|
||||
def create_id():
|
||||
""" Create a string of 40 random characters from the set [a-p],
|
||||
""" Create a string of 40 random characters from the set [a-p],
|
||||
can be used as a unique identifier of objects.
|
||||
|
||||
|
||||
:return: The string of random characters
|
||||
"""
|
||||
ret = ""
|
||||
for _ in range(40):
|
||||
ret += chr(random.randint(0, 15) + ord('a'))
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
def make_temp(string, suffix="", decode=True):
|
||||
""" xmlsec needs files in some cases where only strings exist, hence the
|
||||
need for this function. It creates a temporary file with the
|
||||
string as only content.
|
||||
|
||||
|
||||
:param string: The information to be placed in the file
|
||||
:param suffix: The temporary file might have to have a specific
|
||||
:param suffix: The temporary file might have to have a specific
|
||||
suffix in certain circumstances.
|
||||
:param decode: The input string might be base64 coded. If so it
|
||||
:param decode: The input string might be base64 coded. If so it
|
||||
must, in some cases, be decoded before being placed in the file.
|
||||
:return: 2-tuple with file pointer ( so the calling function can
|
||||
close the file) and filename (which is for instance needed by the
|
||||
close the file) and filename (which is for instance needed by the
|
||||
xmlsec function).
|
||||
"""
|
||||
ntf = NamedTemporaryFile(suffix=suffix)
|
||||
@@ -460,15 +460,15 @@ def x509_rsa_loads(string):
|
||||
def pem_format(key):
|
||||
return "\n".join(["-----BEGIN CERTIFICATE-----",
|
||||
key, "-----END CERTIFICATE-----"])
|
||||
|
||||
|
||||
|
||||
def parse_xmlsec_output(output):
|
||||
""" Parse the output from xmlsec to try to find out if the
|
||||
""" Parse the output from xmlsec to try to find out if the
|
||||
command was successfull or not.
|
||||
|
||||
|
||||
:param output: The output from Popen
|
||||
:return: A boolean; True if the command was a success otherwise False
|
||||
"""
|
||||
"""
|
||||
for line in output.split("\n"):
|
||||
if line == "OK":
|
||||
return True
|
||||
@@ -573,22 +573,22 @@ def verify_signature(enctext, xmlsec_binary, cert_file=None, cert_type="pem",
|
||||
id_attr = ID_ATTR
|
||||
|
||||
_, fil = make_temp(enctext, decode=False)
|
||||
|
||||
|
||||
com_list = [xmlsec_binary, "--verify",
|
||||
"--pubkey-cert-%s" % cert_type, cert_file,
|
||||
"--pubkey-cert-%s" % cert_type, cert_file,
|
||||
"--id-attr:%s" % id_attr, node_name]
|
||||
|
||||
|
||||
if debug:
|
||||
com_list.append("--store-signatures")
|
||||
|
||||
|
||||
if node_id:
|
||||
com_list.extend(["--node-id", node_id])
|
||||
|
||||
|
||||
com_list.append(fil)
|
||||
|
||||
logger.debug("com_list: %s" % com_list)
|
||||
|
||||
if __DEBUG:
|
||||
if __DEBUG:
|
||||
try:
|
||||
print " ".join(com_list)
|
||||
except TypeError:
|
||||
@@ -626,7 +626,7 @@ def read_cert_from_file(cert_file, cert_type):
|
||||
"""
|
||||
if not cert_file:
|
||||
return ""
|
||||
|
||||
|
||||
if cert_type == "pem":
|
||||
line = open(cert_file).read().split("\n")
|
||||
if line[0] == "-----BEGIN CERTIFICATE-----":
|
||||
@@ -660,7 +660,7 @@ def security_context(conf, debug=None):
|
||||
"""
|
||||
if not conf:
|
||||
return None
|
||||
|
||||
|
||||
if debug is None:
|
||||
debug = conf.debug
|
||||
|
||||
@@ -680,28 +680,28 @@ class SecurityContext(object):
|
||||
cert_file="", cert_type="pem", metadata=None,
|
||||
debug=False, template="", encrypt_key_type="des-192",
|
||||
only_use_keys_in_metadata=False):
|
||||
|
||||
|
||||
self.xmlsec = xmlsec_binary
|
||||
|
||||
|
||||
# Your private key
|
||||
self.key_file = key_file
|
||||
self.key_type = key_type
|
||||
|
||||
|
||||
# Your public key
|
||||
self.cert_file = cert_file
|
||||
self.cert_type = cert_type
|
||||
self.my_cert = read_cert_from_file(cert_file, cert_type)
|
||||
|
||||
|
||||
self.metadata = metadata
|
||||
self.only_use_keys_in_metadata = only_use_keys_in_metadata
|
||||
self.debug = debug
|
||||
|
||||
|
||||
if not template:
|
||||
this_dir, this_filename = os.path.split(__file__)
|
||||
self.template = os.path.join(this_dir, "xml", "template.xml")
|
||||
else:
|
||||
self.template = template
|
||||
|
||||
|
||||
self.key_type = encrypt_key_type
|
||||
|
||||
def correctly_signed(self, xml, must=False):
|
||||
@@ -750,7 +750,7 @@ class SecurityContext(object):
|
||||
|
||||
def decrypt(self, enctext):
|
||||
""" Decrypting an encrypted text by the use of a private key.
|
||||
|
||||
|
||||
:param enctext: The encrypted text as a string
|
||||
:return: The decrypted text
|
||||
"""
|
||||
@@ -778,10 +778,10 @@ class SecurityContext(object):
|
||||
ntf.seek(0)
|
||||
return ntf.read()
|
||||
|
||||
def verify_signature(self, enctext, cert_file=None, cert_type="pem",
|
||||
def verify_signature(self, enctext, cert_file=None, cert_type="pem",
|
||||
node_name=NODE_NAME, node_id=None, id_attr=""):
|
||||
""" Verifies the signature of a XML document.
|
||||
|
||||
|
||||
:param enctext: The XML document as a string
|
||||
:param cert_file: The public key that was used to sign the document
|
||||
:param cert_type: The file type of the certificate
|
||||
@@ -795,10 +795,10 @@ class SecurityContext(object):
|
||||
if not cert_file:
|
||||
cert_file = self.cert_file
|
||||
cert_type = self.cert_type
|
||||
|
||||
|
||||
return verify_signature(enctext, self.xmlsec, cert_file, cert_type,
|
||||
node_name, self.debug, node_id, id_attr)
|
||||
|
||||
|
||||
def _check_signature(self, decoded_xml, item, node_name=NODE_NAME,
|
||||
origdoc=None, id_attr="", must=False):
|
||||
#print item
|
||||
@@ -829,12 +829,12 @@ class SecurityContext(object):
|
||||
else:
|
||||
logger.debug("==== Certs from metadata ==== %s: %s ====" % (issuer,
|
||||
certs))
|
||||
|
||||
|
||||
if not certs:
|
||||
raise MissingKey("%s" % issuer)
|
||||
|
||||
#print certs
|
||||
|
||||
|
||||
verified = False
|
||||
for _, pem_file in certs:
|
||||
try:
|
||||
@@ -984,14 +984,14 @@ class SecurityContext(object):
|
||||
|
||||
def correctly_signed_response(self, decoded_xml, must=False, origdoc=None):
|
||||
""" Check if a instance is correctly signed, if we have metadata for
|
||||
the IdP that sent the info use that, if not use the key that are in
|
||||
the IdP that sent the info use that, if not use the key that are in
|
||||
the message if any.
|
||||
|
||||
|
||||
:param decoded_xml: The SAML message as a XML string
|
||||
:param must: Whether there must be a signature
|
||||
:return: None if the signature can not be verified otherwise an instance
|
||||
"""
|
||||
|
||||
|
||||
response = samlp.any_response_from_string(decoded_xml)
|
||||
if not response:
|
||||
raise TypeError("Not a Response")
|
||||
@@ -1017,16 +1017,16 @@ class SecurityContext(object):
|
||||
except Exception, exc:
|
||||
logger.error("correctly_signed_response: %s" % exc)
|
||||
raise
|
||||
|
||||
|
||||
return response
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# SIGNATURE PART
|
||||
#--------------------------------------------------------------------------
|
||||
def sign_statement_using_xmlsec(self, statement, klass_namn, key=None,
|
||||
def sign_statement_using_xmlsec(self, statement, klass_namn, key=None,
|
||||
key_file=None, nodeid=None, id_attr=""):
|
||||
"""Sign a SAML statement using xmlsec.
|
||||
|
||||
|
||||
:param statement: The statement to be signed
|
||||
:param key: The key to be used for the signing, either this or
|
||||
:param key_file: The file where the key can be found
|
||||
@@ -1043,14 +1043,14 @@ class SecurityContext(object):
|
||||
|
||||
if not key and not key_file:
|
||||
key_file = self.key_file
|
||||
|
||||
|
||||
_, fil = make_temp("%s" % statement, decode=False)
|
||||
|
||||
ntf = NamedTemporaryFile()
|
||||
|
||||
com_list = [self.xmlsec, "--sign",
|
||||
com_list = [self.xmlsec, "--sign",
|
||||
"--output", ntf.name,
|
||||
"--privkey-pem", key_file,
|
||||
"--privkey-pem", key_file,
|
||||
"--id-attr:%s" % id_attr, klass_namn
|
||||
#"--store-signatures"
|
||||
]
|
||||
@@ -1080,7 +1080,7 @@ class SecurityContext(object):
|
||||
def sign_assertion_using_xmlsec(self, statement, key=None, key_file=None,
|
||||
nodeid=None, id_attr=""):
|
||||
"""Sign a SAML assertion using xmlsec.
|
||||
|
||||
|
||||
:param statement: The statement to be signed
|
||||
:param key: The key to be used for the signing, either this or
|
||||
:param key_file: The file where the key can be found
|
||||
@@ -1126,7 +1126,7 @@ class SecurityContext(object):
|
||||
|
||||
if not item.signature:
|
||||
item.signature = pre_signature_part(sid, self.cert_file)
|
||||
|
||||
|
||||
statement = self.sign_statement_using_xmlsec(statement,
|
||||
class_name(item),
|
||||
key=key,
|
||||
@@ -1134,7 +1134,7 @@ class SecurityContext(object):
|
||||
nodeid=id,
|
||||
id_attr=id_attr)
|
||||
return statement
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
@@ -1143,7 +1143,7 @@ def pre_signature_part(ident, public_key=None, identifier=None):
|
||||
If an assertion is to be signed the signature part has to be preset
|
||||
with which algorithms to be used, this function returns such a
|
||||
preset part.
|
||||
|
||||
|
||||
:param ident: The identifier of the assertion, so you know which assertion
|
||||
was signed
|
||||
:param public_key: The base64 part of a PEM file
|
||||
@@ -1157,26 +1157,26 @@ def pre_signature_part(ident, public_key=None, identifier=None):
|
||||
trans1 = ds.Transform(algorithm=ds.ALG_EXC_C14N)
|
||||
transforms = ds.Transforms(transform=[trans0, trans1])
|
||||
digest_method = ds.DigestMethod(algorithm=ds.DIGEST_SHA1)
|
||||
|
||||
|
||||
reference = ds.Reference(uri="#%s" % ident, digest_value=ds.DigestValue(),
|
||||
transforms=transforms, digest_method=digest_method)
|
||||
|
||||
|
||||
signed_info = ds.SignedInfo(signature_method=signature_method,
|
||||
canonicalization_method=canonicalization_method,
|
||||
reference=reference)
|
||||
|
||||
|
||||
signature = ds.Signature(signed_info=signed_info,
|
||||
signature_value=ds.SignatureValue())
|
||||
|
||||
|
||||
if identifier:
|
||||
signature.id = "Signature%d" % identifier
|
||||
|
||||
|
||||
if public_key:
|
||||
x509_data = ds.X509Data(
|
||||
x509_certificate=[ds.X509Certificate(text=public_key)])
|
||||
key_info = ds.KeyInfo(x509_data=x509_data)
|
||||
signature.key_info = key_info
|
||||
|
||||
|
||||
return signature
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user